GUACAMOLE-1347: Merge migrate from DocBook to Sphinx.
diff --git a/.dockerignore b/.dockerignore
index fd35d91..194ce7d 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,4 +1,2 @@
.git/
-book/
-html/
-docbook-xsl
+build/
diff --git a/.gitignore b/.gitignore
index 55e8b27..d304cc9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-/html
-/book
-/docbook-xsl
+/build
*~
+__pycache__
diff --git a/Dockerfile b/Dockerfile
index 7390cc2..dac3e57 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -25,51 +25,20 @@
# Set this build arg to any of the available version labels for the httpd image
ARG HTTPD_VERSION=2.4
-# Perform the build itself on a Debian base
-FROM debian:stretch AS builder
-
-# Set the path for docbook, as required by the Makefile
-ENV DOCBOOK_PATH=/usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/
-
-# Install build dependencies
-RUN \
- apt-get update && \
- apt-get install -y make xsltproc fop docbook-xsl
-
-# Make the directory structure that will be produced by the build so that
-# directories will exist regardless of which target is selected. This ensures
-# that the COPY commands in the second stage of the build will succeed even
-# if the target selected does not include all build variants.
-#
-# This RUN is a separate command from the previous RUN command, so that changes
-# to the build structure that might result in the need to change the directories
-# created here will not invalidate the build cache from the preceding command
-# that installs dependences (which is a time consuming step).
-#
-RUN \
- mkdir -p /manual/html && \
- mkdir -p /manual/book
+# Perform the build itself using Python+Sphinx
+FROM sphinxdoc/sphinx AS builder
+RUN pip3 install sphinx-rtd-theme sphinx-inline-tabs myst-parser
# Set the working directory for the remainder of the build process
WORKDIR /manual
-# Default build target for the make
-#
-# It might be tempting to move this command to the top of the Dockerfile,
-# but by doing so, any time a different target is selected, the build cache
-# for the layer that installs all build dependencies will be invalidated.
-#
-ARG TARGET=html
-
# Copy the manual source into the working directory and build it
COPY ./ ./
-RUN make ${TARGET}
+RUN make
# For the runtime image, use the official Apache httpd image
FROM httpd:${HTTPD_VERSION}
# Copy any HTML generated by the build into httpd's document root
-COPY --from=builder /manual/html/ /usr/local/apache2/htdocs/
+COPY --from=builder /manual/build/html/ /usr/local/apache2/htdocs/
-# Copy any PDF generated by the build into http's document root
-COPY --from=builder /manual/book/ /usr/local/apache2/htdocs/
diff --git a/Makefile b/Makefile
index 0ab5731..f50e2bd 100644
--- a/Makefile
+++ b/Makefile
@@ -17,58 +17,32 @@
# under the License.
#
-.PHONY: all clean book html
+.PHONY: all clean html
#
# Build entire manual
#
-all: html book
+all: html
#
# Clean build artifacts
#
clean:
- $(RM) docbook-xsl
- $(RM) -R html/ book/
- $(RM) *.pdf *.fo
-
-#
-# Link Docbook XSL into build, if available
-#
-
-docbook-xsl:
- test -e "$(DOCBOOK_PATH)" && ln -s "$(DOCBOOK_PATH)" docbook-xsl
+ $(RM) -R build/
# All files which the build depends on
-XML_FILES=$(shell find -path "./src/*" -name "*.xml")
+MD_FILES=$(shell find -path "./src/*" -name "*.md")
+RST_FILES=$(shell find -path "./src/*" -name "*.rst")
PNG_FILES=$(shell find -path "./src/*" -name "*.png")
#
# HTML manual build
#
-html: html/index.html html/gug.css html/images
+html: build/html/index.html
-html/index.html: $(XML_FILES) src/site.xslt docbook-xsl
- cd src; xsltproc -o ../html/ --xinclude site.xslt gug.xml
-
-html/gug.css: src/gug.css
- mkdir -p html; cp src/gug.css html/
-
-html/images: $(PNG_FILES)
- mkdir -p html/images; cp -fv $(PNG_FILES) html/images/
-
-#
-# PDF manual build
-#
-
-book: book/gug.pdf
-
-book/gug.fo: $(XML_FILES) src/book.xslt docbook-xsl
- cd src; xsltproc -o ../book/gug.fo --xinclude book.xslt gug.xml
-
-book/gug.pdf: book/gug.fo
- cd src; fop -c fop-conf.xml -fo ../book/gug.fo -pdf ../book/gug.pdf
+build/html/index.html: $(PNG_FILES) $(RST_FILES) $(MD_FILES)
+ sphinx-build -b html -d build/doctrees src/ build/html
diff --git a/README b/README
deleted file mode 100644
index c021f8d..0000000
--- a/README
+++ /dev/null
@@ -1,138 +0,0 @@
-
-------------------------------------------------------------
- About this README
-------------------------------------------------------------
-
-This README is intended to document the build process of the Apache Guacamole
-manual for technical users who wish to contribute or who simply wish to build
-the manual themselves.
-
-The latest version of the manual is provided on the Guacamole web site, and
-snapshot copies of each release are included in the release archives:
-
- http://guacamole.apache.org/
-
-
-------------------------------------------------------------
- What is guacamole-manual?
-------------------------------------------------------------
-
-The guacamole-manual package is the base documentation for the entire Guacamole
-stack. It is written in DocBook, an XML schema commonly used for authoring
-manuals and technical documentation.
-
-The build process involves running the Guacamole manual XML through an XSLT
-processor called "xsltproc", applying the standard DocBook XSL stylesheets.
-
-
-------------------------------------------------------------
- Building the manual
-------------------------------------------------------------
-
-
-1) Ensure the DocBook XSL stylesheets are installed
-
- Most Linux distributions will provide a "docbook-xsl" or similarly-named
- package which install the DocBook stylesheets in a system-wide manner. You
- will need to either install these packages, or download the DocBook XSL
- stylesheets yourself:
-
- https://sourceforge.net/projects/docbook/files/docbook-xsl/
-
-2) Ensure the DOCBOOK_PATH environment variable is set
-
- The manual build process depends on an environment variable, DOCBOOK_PATH,
- which points to the directory in which the DocBook XSL files can be found.
-
- This will be the directory that contains the following files:
-
- fo/docbook.xsl
- html/chunk.xsl
-
- $ export DOCBOOK_PATH=/usr/share/sgml/docbook/xsl-ns-stylesheets-1.78.1
-
-3) Ensure xsltproc and fop are installed
-
- If you do not have xsltproc, the manual will not build. The provided
- Makefile depends entirely on using xsltproc to process the Guacamole manual
- XML through the installed DocBook stylesheets.
-
- Although not required for building the HTML manual, if you do not have fop
- (Apache FOP), the PDF version of the manual cannot be built. The build
- process uses fop to transform a ".fo" file into the PDF.
-
-4) Run make
-
- $ make
-
- The manual will now be built using xsltproc. Once complete, the entire
- HTML version of the manual will be available within the "html" directory in
- the root directory of the source tree, and the PDF version will be
- available within the "book" directory as "gug.pdf".
-
- The default build target, "all", will build both the HTML and PDF versions
- of the manual. If you only wish to build the HTML manual, you can specify
- the "html" target explicitly:
-
- $ make html
-
- Similarly, if you only wish to build the PDF, you can force this by
- explicitly specifying the "book" target:
-
- $ make book
-
-
-------------------------------------------------------------
- Building and viewing the manual using Docker
-------------------------------------------------------------
-
-The guacamole-manual package includes a Dockerfile that can be used to build
-an Apache httpd Docker image that contains the Guacamole user manual.
-
-By building and running the resulting container, a developer can work on the
-user manual without the need to install docbook and related dependencies on
-his/her workstation. The resulting container can also be used to serve the
-manual to Guacamole users on a network.
-
-Docker CE version 1.6 or later is required to build the image.
-
-Build the Guacamole manual container image by running the following command in
-the directory that contains this Dockerfile:
-
- $ docker image build -t guacamole/manual .
-
-Run the resulting container using the following command:
-
- $ docker container run -p 8080:80 guacamole/manual
-
-You'll see some startup messages from Apache httpd on your terminal when you
-start up the container. Once the container is running you can then view the
-HTML version of the manual by accessing http://localhost:8080 using your web
-browser.
-
-If another process on the host is already using port 8080, you will need to
-change the corresponding argument in the command used to start the container.
-
-As a developer working on the documentation, it will be necessary to stop the
-container and run the build again each time you wish to see changes you've
-made to the documentation source.
-
-By default, the container image will contain only the HTML variant of the
-Guacamole user manual. If you also wish to serve the PDF variant, use the
-following command to build container image
-
- $ docker image build --build-arg TARGET=all -t guacamole/manual .
-
-You can view the PDF variant of the manual by accessing
-http://localhost:8080/gug.pdf using your web browser.
-
-
-------------------------------------------------------------
- Reporting problems
-------------------------------------------------------------
-
-Please report any bugs encountered by opening a new issue in the JIRA system
-hosted at:
-
- https://issues.apache.org/jira/browse/GUACAMOLE
-
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7a3aa95
--- /dev/null
+++ b/README.md
@@ -0,0 +1,131 @@
+About this README
+=================
+
+This README is intended to document the build process of the Apache Guacamole
+manual for technical users who wish to contribute or who simply wish to build
+the manual themselves.
+
+The [latest version of the manual](http://guacamole.apache.org/doc/gug/) is
+provided on the [Guacamole web site](http://guacamole.apache.org/), and
+snapshot copies of each release are included in the [release
+archives](http://guacamole.apache.org/releases/).
+
+
+What is guacamole-manual?
+=========================
+
+The guacamole-manual package is the base documentation for the entire Guacamole
+stack. It is largely written in [the "MyST" flavor of Markdown](https://myst-parser.readthedocs.io/en/latest/index.html),
+with portions of the documentation written in reStructuredText where necessary
+(the Guacamole protocol reference).
+
+MyST was chosen as the primary format because:
+
+ * As a variant of Markdown, it will be widely approachable and familiar.
+ * It is supported by Sphinx.
+ * It provides additional syntax for the features of reStructuredText that are
+ absent from standard Markdown (like admonitions).
+ * It provides the features of Markdown that are absent from reStructuredText
+ (like nested inline formatting, including formatting within links or links
+ within formatted text).
+
+reStructuredText is occasionally necessary because:
+
+ * [MyST does not support docstring field lists](https://github.com/executablebooks/MyST-Parser/issues/163#issuecomment-640008632),
+ a feature of reStructuredText required for documenting APIs. We use this
+ feature for documenting the Guacamole protocol.
+ * The MyST solution to supporting docstrings is [embedding blocks of
+ reStructuredText](https://myst-parser.readthedocs.io/en/latest/using/howto.html#use-sphinx-ext-autodoc-in-markdown-files).
+
+The build process involves running the Guacamole manual source through the
+tooling provided by the Sphinx project, in particular "sphinx-build".
+
+
+Build requirements
+==================
+
+Building the Guacamole manual from source requires:
+
+ * **Python 3.8 or later**
+ * An implementation of "make", such as [GNU
+ Make](https://www.gnu.org/software/make/)
+ * [Sphinx](https://pypi.org/project/Sphinx/)
+ * [sphinx-rtd-theme](https://pypi.org/project/sphinx-rtd-theme/) (the
+ ReadTheDocs theme for Sphinx),
+ * [sphinx-inline-tabs](https://pypi.org/project/sphinx-inline-tabs/)
+ * [myst-parser](https://pypi.org/project/myst-parser/)
+
+The required Python packages can be installed using the "pip" package manager:
+
+```console
+$ pip install sphinx sphinx-rtd-theme sphinx-inline-tabs myst-parser
+```
+
+On some systems, the Python 3 version of "pip" may instead be named "pip3", to
+maintain compatability with users and scripts that expect Python 2:
+
+```console
+$ pip3 install sphinx sphinx-rtd-theme sphinx-inline-tabs myst-parser
+```
+
+Building the manual
+===================
+
+If all build requirements have beein installed, the manual can be build by
+simply running "make":
+
+```console
+$ make
+```
+
+The manual will then be built using Sphinx. Once complete, the entire HTML
+version of the manual will be available within the `build/html/` directory in
+the root directory of the source tree.
+
+Building and viewing the manual using Docker
+============================================
+
+The guacamole-manual package includes a `Dockerfile` that can be used to build
+an Apache httpd Docker image that contains the Guacamole user manual.
+
+By building and running the resulting container, a developer can work on the
+user manual without the need to install Sphinx on their workstation. The
+resulting container can also be used to serve the manual to Guacamole users on
+a network.
+
+**Docker CE version 1.6 or later is required to build the image.**
+
+Build the Guacamole manual container image by running the following command in
+the directory that contains this Dockerfile:
+
+```console
+$ docker image build -t guacamole/manual .
+```
+
+Run the resulting container using the following command:
+
+```console
+$ docker container run -p 8080:80 guacamole/manual
+```
+
+You'll see some startup messages from Apache httpd on your terminal when you
+start up the container. Once the container is running you can then view the
+HTML version of the manual by accessing http://localhost:8080 using your web
+browser.
+
+If another process on the host is already using port 8080, you will need to
+change the corresponding argument in the command used to start the container.
+
+As a developer working on the documentation, it will be necessary to stop the
+container and run the build again each time you wish to see changes you've
+made to the documentation source.
+
+
+Reporting problems
+==================
+
+Please report any bugs encountered by opening a new issue in the JIRA system
+hosted at:
+
+<https://issues.apache.org/jira/browse/GUACAMOLE>
+
diff --git a/src/_static/gug.css b/src/_static/gug.css
new file mode 100644
index 0000000..4e24f42
--- /dev/null
+++ b/src/_static/gug.css
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* Do not include border/background around code literals */
+.rst-content code {
+ border: none;
+ background: transparent;
+ padding: 0;
+}
+
+/* Use header font size for code literals in headers */
+.rst-content h1 code.literal,
+.rst-content h2 code.literal,
+.rst-content h3 code.literal,
+.rst-content h4 code.literal,
+.rst-content h5 code.literal,
+.rst-content h6 code.literal {
+ font-size: 100%;
+}
+
+/* Add border/background around replacable parts of code literals */
+.rst-content code.samp em {
+ background: #fff;
+ border: 1px solid #e1e4e5;
+ padding: 2px;
+ font-style: normal;
+ font-weight: bold;
+}
+
+/* Allow links containing code to be differentiated from normal text containing
+ * code */
+.rst-content a[href] code.literal {
+ color: inherit;
+}
+
diff --git a/src/_templates/footer.html b/src/_templates/footer.html
new file mode 100644
index 0000000..2b1eece
--- /dev/null
+++ b/src/_templates/footer.html
@@ -0,0 +1,10 @@
+{% extends '!footer.html' %}
+
+{% block contentinfo %}
+ {%- if show_copyright %}
+ <p>Copyright © {{ copyright_year }} <a href="http://www.apache.org/">The Apache Software Foundation</a>,
+ Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
+ Apache Guacamole, Guacamole, Apache, the Apache feather logo, and the Apache Guacamole project logo are
+ trademarks of The Apache Software Foundation.</p>
+ {%- endif %}
+{% endblock %}
diff --git a/src/adhoc-connections.md b/src/adhoc-connections.md
new file mode 100644
index 0000000..68631ab
--- /dev/null
+++ b/src/adhoc-connections.md
@@ -0,0 +1,139 @@
+Ad-hoc Connections
+==================
+
+The quickconnect extension provides a connection bar on the Guacamole Client
+home page that allows users to type in the URI of a server to which they want
+to connect and the client will parse the URI and immediately establish the
+connection. The purpose of the extension is to allow situations where
+administrators want to allow users the flexibility of establishing their own
+connections without having to grant them access to edit connections or even to
+have to create the connections at all, aside from typing the URI.
+
+:::{important}
+There are several implications of using this extension that should be
+well-understood by administrators prior to implementing it:
+
+* Connections established with this extension are created in-memory and only
+ persist until the Guacamole session ends.
+
+* Connections created with this extension are not accessible to other users,
+ and cannot be shared with other users.
+
+* This extension provides no functionality for authenticating users - it does
+ not allow anonymous logins, and requires that users are successfully
+ authenticated by another authentication module before it can be used.
+
+* The extension provides users the ability not only to establish connections,
+ but also to set any of the parameters for a connection. There are security
+ implications for this - for example, RDP file sharing can be used to pass
+ through any directory available on the server running guacd to the remote
+ desktop. This should be taken into consideration when enabling this extension
+ and making sure that guacd is configured in a way that does not compromise
+ sensitive system files by allowing access to them.
+:::
+
+(quickconnect-downloading)=
+
+Downloading the quickconnect extension
+--------------------------------------
+
+The quickconnect extension is available separately from the main
+`guacamole.war`. The link for this and all other officially-supported and
+compatible extensions for a particular version of Guacamole are provided in the
+release notes for that version. You can find the release notes for current
+versions of Guacamole here: <http://guacamole.apache.org/releases/>.
+
+The quickconnect extension is packaged as a `.tar.gz` file containing only the
+extension itself, `guacamole-auth-quickconnect-1.3.0.jar`, which must
+ultimately be placed in `GUACAMOLE_HOME/extensions`.
+
+(installing-quickconnect)=
+
+Installing the quickconnect extension
+-------------------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located within
+the `GUACAMOLE_HOME/extensions` directory. *If you are unsure where
+`GUACAMOLE_HOME` is located on your system, please consult
+[](configuring-guacamole) before proceeding.*
+
+To install the extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+ exist.
+
+2. Place the `guacamole-auth-quickconnect-1.3.0.jar` file in the
+ `GUACAMOLE_HOME/extensions` directory.
+
+(guac-quickconnect-config)=
+
+### Configuring Guacamole for the quickconnect extension
+
+The quickconnect extension has two configuration properties that allow for
+controlling what connection parameters can be used in the URIs that are opened
+with the quickconnect extension:
+
+`quickconnect-allowed-parameters`
+: An optional list of parameters that are allowed to be used by connections
+ that are created and accessed via the quickconnect extension. If this
+ property is present, only parameters in this list will be allowed. If this
+ property is absent, any/all parameters will be allowed unless explicitly
+ denied using the `quickconnect-denied-parameters` property.
+
+`quickconnect-denied-parameters`
+: An optional list of parameters that are explicitly denied from being used by
+ connections created and accessed via the quickconnect extension. If this
+ property is present, any parameters in this list will be removed from the
+ connection configuration when it is created, *even if those parameter are
+ listed above in the `quickconnect-allowed-parameters` property.* If this
+ property is not present, no connection parameters will be explicitly denied.
+
+(completing-quickconnect-install)=
+
+### Completing the installation
+
+Guacamole will only load newly-installed extensions during startup, so your
+servlet container will need to be restarted before the quickconnect extension
+can be used. *Doing this will disconnect all active users, so be sure that it
+is safe to do so prior to attempting installation.* When ready, restart your
+servlet container and give the extension a try.
+
+(using-quickconnect)=
+
+Using the quickconnect extension
+--------------------------------
+
+The quickconnect extension provides a field on the home page that allows you to
+enter a Uniform Resource Identifier (URI) to create a connection. A URI is in
+the form:
+
+{samp}`{protocol}://{username}:{password}@{host}:{port}/?{parameters}`
+
+The `protocol` field can have any of the protocols supported by Guacamole, as
+documented in [](configuring-guacamole). Many of the protocols define a default
+`port` value, with the exception of VNC. The `parameters` field can specify any
+of the protocol-specific parameters as documented on the configuration page.
+
+To establish a connection, simply type in a valid URI and either press "Enter"
+or click the connect button. This extension will parse the URI and create a new
+connection, and immediately start that connection in the current browser.
+
+Here are a few examples of URIs:
+
+`ssh://linux1.example.com/`
+: Connect to the server linux1.example.com using the SSH protocol on the
+ default SSH port (22). This will result in prompting for both username and
+ password.
+
+`vnc://linux1.example.com:5900/`
+: Connect to the server linux1.example.com using the VNC protocol and
+ specifying the port as 5900.
+
+`rdp://localuser@windows1.example.com/?security=rdp&ignore-cert=true&disable-audio=true&enable-drive=true&drive-path=/mnt/usb`
+: Connect to the server windows1.example.com using the RDP protocol and the
+ user "localuser". This URI also specifies several RDP-specific parameters on
+ the connection, including forcing security mode to RDP (security=rdp), ignoring
+ any certificate errors (ignore-cert=true), disabling audio pass-through
+ (disable-audio=true), and enabling filesystem redirection (enable-drive=true)
+ to the /mnt/usb folder on the system running guacd (drive-path=/mnt/usb).
+
diff --git a/src/administration.md b/src/administration.md
new file mode 100644
index 0000000..b725829
--- /dev/null
+++ b/src/administration.md
@@ -0,0 +1,314 @@
+Administration
+==============
+
+Users, user groups, connections, and active sessions can be administered from
+within the web interface if the underlying authentication module supports this.
+The only officially-supported authentication modules supporting this are the
+database extensions, which are documented in [](jdbc-auth).
+
+If you are using the default authentication mechanism, or another
+authentication extension, this chapter probably does not apply to you, and the
+management options will not be visible in the Guacamole interface. If, on the
+other hand, you are using one of the database authentication providers, and you
+are logged in as a user with sufficient privileges, you will see management
+sections listed within the settings screen:
+
+
+
+Clicking any of these options will take you to a corresponding management
+section where you can perform administrative tasks.
+
+(session-management)=
+
+Managing sessions
+-----------------
+
+Clicking "Active Sessions" navigates to the session management screen. The
+session management screen displays all active sessions and allows system
+administrators to kill them as needed.
+
+When any user accesses a particular remote desktop connection, a unique session
+is created and will appear in the list of active sessions in the session
+management screen. Each active session is displayed in a sortable table,
+showing the corresponding user's username, how long the session has been
+active, the IP address of the machine from which the user is connecting, and
+the name of the connection being used.
+
+
+
+To kill one or more sessions, select the sessions by clicking their checkboxes.
+Once all desired sessions have been selected, clicking "Kill Sessions" will
+immediately disconnect those users from the associated connection.
+
+(filtering-sessions)=
+
+### Filtering and sorting
+
+The table can be resorted by clicking on the column headers. Clicking any
+column will resort the table by the values within that column, while clicking a
+column which is already sorted will toggle between ascending and descending
+order.
+
+The content of the table can be limited through search terms specified in the
+"Filter" field. Entering search terms will limit the table to only sessions
+containing those terms. For example, to list only connections by the user
+"guacadmin" which have been active since March, 2015, you would enter:
+"guacadmin 2015-03". Beware that if a search term needs to contain spaces, it
+must be enclosed in double quotes to avoid being interpreted as multiple terms.
+
+
+
+If you wish to narrow the content of the table to only those connections which
+originate from a particular block of IP addresses, you can do this by
+specifying the block in standard CIDR notation, such "10.0.0.0/8" or
+"2001:db8:1234::/48". This will work with both IPv4 and IPv6 addresses.
+
+
+
+Connection history
+------------------
+
+Clicking "History" navigates to the connection history screen. The connection
+history screen displays a table of the most recent connections, including the
+user that used that connection, the time the connection began, and how long the
+connection was used.
+
+
+
+(filtering-history)=
+
+### Filtering and sorting
+
+Initially, the connection history table will display only the most recent
+history records. You can page through these records to see how and when
+Guacamole has been used.
+
+Just as with the table of active sessions described earlier, the table of
+history records can be resorted by clicking on the column headers or filtered
+by entering search terms within the "Filter" field.
+
+The same filtering format applies - a search term containing spaces must be
+enclosed in double quotes to avoid being interpreted as multiple terms, and
+only history records which contain each term will be included in the history
+table. Unlike the table of active sessions, however, the filter will only take
+effect once you click the "Search" button. This is due to the nature of the
+connection history, as the number of records may be quite extensive.
+
+(user-management)=
+
+User management
+---------------
+
+Clicking "Users" within the list of settings sections will take you to the user
+management screen. Here you can add new users, edit the properties and
+privileges of existing users, and view the times that each user last logged in.
+If you have a large number of users, you can also enter search terms within the
+"Filter" field to filter the list of users by username.
+
+To add a new user, click the "New User" button. This will take you to a screen
+where you will be allowed to enter the details of the new user, such as the
+password and username. Note that, unless you specify otherwise, the new user
+will have no access to any existing connections, nor any administrative
+privileges, and you will need to manually set the user's password before they
+will be able to log in.
+
+
+
+To edit a user, just click on the user you wish to edit. You will be taken to a
+screen which allows you to change the user's password, expire their password
+(such that it must be changed at next login), add or remove administrative
+permissions, and add or remove read access to specific connections, sharing
+profiles, or groups. If you are managing a large number of connections or
+groups and wish to reduce the size of the list displayed, you can do so by
+specifying search terms within the "Filter" field. Groups will be filtered by
+name and connections will be filtered by name or protocol.
+
+If you have delete permission on the user, you will also see a "Delete" button.
+Clicking this button will permanently delete the user. Alternatively, if you
+only wish to temporarily disable the account, checking "Login disabled" will
+achieve the same effect while not removing the user entirely. If they attempt
+to log in, the attempt will be rejected as if their account did not exist at
+all.
+
+
+
+(user-group-membership)=
+
+### Editing group membership
+
+When editing a user, the groups that user is a member of may be modified within
+the "Groups" section. By default, only groups that the user is already a member
+of will be displayed. If you have permission to modify the user's membership
+within a group, an "X" icon will be available next to that group's name.
+Clicking the "X" will remove the user from that group, taking effect after the
+user is saved.
+
+To add users to a group, the arrow next to the list of groups must be clicked
+to expand the section and reveal all available groups. Available groups may
+then be checked/unchecked to modify the user's membership within those groups:
+
+
+
+If you have a large number of available groups, you can also enter search terms
+within the "Filter" field to filter the list of groups by name.
+
+(user-group-management)=
+
+User group management
+---------------------
+
+Clicking "Groups" within the list of settings sections will take you to the
+user group management screen. Here you can add new groups and edit the
+properties and privileges of existing groups. If you have a large number of
+user groups, you can also enter search terms within the "Filter" field to
+filter the list of groups by name:
+
+
+
+To add a new group, click the "New Group" button. This will take you to a
+screen where you will be allowed to enter the details of the new group,
+including membership and any permissions that members of the group should have.
+
+To edit a group, just click on the group you wish to edit. You will be taken to
+a screen which allows you to modify membership, add or remove administrative
+permissions, and add or remove read access to specific connections, sharing
+profiles, or connection groups. If you are managing a large number of
+connections or groups and wish to reduce the size of the list displayed, you
+can do so by specifying search terms within the "Filter" field. Connection
+groups will be filtered by name and connections will be filtered by name or
+protocol.
+
+If you have delete permission on the group, you will also see a "Delete"
+button. Clicking this button will permanently delete the group. Alternatively,
+if you only wish to temporarily disable the effects of membership in the group,
+checking "Disabled" will achieve the same effect while not removing the group
+entirely.
+
+
+
+### Group membership of groups
+
+Managing the group membership of groups is more complex than that of users, as
+groups may contain both users and groups, with permissions from parent groups
+possibly being inherited. Parent groups, member groups, and member users, can
+all be managed identically to the [group memberships of users](user-group-membership),
+with a corresponding section dedicated to each within the user group editor:
+
+
+
+Note that it is ultimately up to the extension providing the group to determine
+how permissions granted to that group are inherited, if at all. The [database
+authentication extension](jdbc-auth) implements full recursive inheritance of
+group permissions, with permissions granted to a group being granted to all
+members/descendants of that group, regardless of how deeply those members are
+nested.
+
+(connection-management)=
+
+Connections and connection groups
+---------------------------------
+
+Clicking "Connections" within the list of settings sections will take you to
+the connection management screen. The connection management screen allows
+administrators to create and edit connections, sharing profiles, and connection
+groups. If you have a large number of connections, you can also enter search
+terms within the "Filter" field to filter the list of connections by name or
+protocol.
+
+To add a new connection or connection group, click the "New Connection" or "New
+Group" button, or the "New Connection" or "New Group" placeholders which appear
+when you expand an existing connection group. These options will take you to a
+screen where you will be allowed to enter the details of the new object, such
+as its location, parameters, and name. This name should be descriptive, but
+must also be unique with respect to other objects in the same location.
+
+Once you click "Save", the new object will be added, but will initially only be
+usable by administrators and your current user. To grant another user access to
+the new connection or connection group, you must [edit that user](user-management)
+or [a user group that the user is a member of](user-group-management), checking
+the box corresponding to the connection or connection group you created.
+
+
+
+Editing connections, sharing profiles, and connection groups works identically
+to editing a user. Click on the object you wish to edit, and you will be taken
+to screen which allows you to edit it. The screen will display all properties
+of the object, including its usage history, if applicable.
+
+If you have delete permission on the object, you will also see a "Delete"
+button. Clicking this button will permanently delete the object being edited.
+
+
+
+(connection-group-management)=
+
+### Connection organization and balancing
+
+Connection groups can be either "organizational" or "balancing". Each group can
+contain any number of other connections or groups, but the semantics of the
+group change depending on the type.
+
+An organizational group behaves exactly as a folder or directory in a file
+system. It simply contains connections and other groups, but provides no other
+behavior. Clicking on an organizational group within a connection list will
+expand the group, revealing its contents.
+
+A balancing group behaves as a connection. It dynamically balances load across
+the connections it contains, choosing the connection with the fewest number of
+active users. Unlike organizational groups, clicking on a balancing group
+causes a new connection to be opened. The actual underlying connection used
+depends on which connection has the least load at the time the group was
+clicked, and whether session affinity is enabled on that group.
+
+Enabling session affinity for a balancing group ensures that users are
+consistently routed to the same underlying connections until they log out of
+Guacamole. The load balancing behavior of the balancing group will apply only
+for the first time a particular user connects to the group. If your users may
+lose their desktop state if they are routed to a different underlying
+connection, this option should be enabled.
+
+
+
+### Connection sharing
+
+The ability to share a connection is governed through the use of "sharing
+profiles". If a sharing profile is created for a connection, users with access
+to both that connection and that sharing profile will be able to share the
+connection with other users by [generating connection sharing
+links](client-share-menu), even if those users do not otherwise have user
+accounts within Guacamole.
+
+The name of the sharing profile will be presented as an option within the
+[share menu](client-share-menu) for any users with access, while the level of
+access granted to users of generated share links will be dictated by the
+parameters specified for the sharing profile.
+
+:::{important}
+*The only extension which ships with Guacamole and implements enough of the
+[Guacamole extension API](guacamole-ext) to share its connections is the
+[database authentication extension](jdbc-auth).* If you wish to share
+connections (or allow your users to share connections), you will need to use
+the database authentication extension to store those connections.
+
+If you need to use other authentication schemes, keep in mind that the database
+authentication extension can be used [alongside other extensions](ldap-and-database),
+with the database handling connection storage and permissions only. Writing
+your own extension which supports sharing is another alternative, though that
+may be overly complicated if everything you need is already provided.
+:::
+
+Unlike connections and groups, there is no "New Sharing Profile" button.
+Sharing profiles are created through clicking the "New Sharing Profile"
+placeholders which appear when connections are expanded. Just as
+expanding a connection group reveals the connections or groups therein,
+expanding a connection reveals the sharing profiles associated with that
+connection. This holds true with both [the list of connections in the
+connection management screen](connection-management) and [the list of
+connections in the user editor](user-management).
+
+Creating or editing a sharing profile is virtually identical to creating or
+editing a connection, with the exception that not all connection parameters are
+available:
+
+
+
diff --git a/src/appendices/faq.xml b/src/appendices/faq.xml
deleted file mode 100644
index 8216f35..0000000
--- a/src/appendices/faq.xml
+++ /dev/null
@@ -1,268 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<appendix xml:id="faq"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
-
- <title>FAQ</title>
-
- <qandaset>
-
- <qandaentry>
- <question>
-
- <para>Where does the name "Guacamole" come from? </para>
-
- </question>
- <answer>
-
- <para>The name was chosen arbitrarily from a random utterance in a conversation with
- a member of the project. </para>
-
- <para>When the project reached the point where it was growing out of the
- proof-of-concept phase, and needed a real home on the internet, we needed to
- think of a name to register the project under. </para>
-
- <para>Several acronyms were toyed with and discarded. We tried anagrams, but all
- were too wordy and complex. We considered naming the project after a fish or an
- animal, and after suggesting the guanaco, James Muehlner, a developer of the
- project, suggested (randomly): "guacamole". </para>
-
- <para>The name had a nice ring, we weren't embarrassed to use it, and it stuck. </para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>What does "clientless" mean? </para>
-
- </question>
- <answer>
-
- <para>The term "clientless" means that no specific client is needed. A Guacamole
- user needs only have an HTML5 web browser installed, which is exceedingly
- common; virtually all modern computers and mobile devices have such a browser
- installed by default. </para>
-
- <para>In this sense, Guacamole is "clientless" in that it does not require any
- additional software to be installed beyond what is considered standard for any
- computer. </para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>Does Guacamole use WebSocket? </para>
-
- </question>
- <answer>
- <para>Guacamole uses either WebSocket or plain HTTP, whichever is supported by both
- the browser and your servlet container. If WebSocket cannot be used for any
- reason, Guacamole will fall back to using HTTP.</para>
-
- <para>Historically, Guacamole had no WebSocket support at all. This was due to a
- lack of browser support and lack of a true standard. Overall, it didn't matter
- as there really wasn't any need: the tunnel used by Guacamole when WebSocket is
- not available is largely equivalent to WebSocket in terms of efficiency and
- latency, and is more compatible with proxies and existing browsers.</para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>I have Tomcat (or some other servlet container) set up behind a proxy (like
- mod_proxy) and cannot connect to Guacamole. Why? How do I solve this? </para>
-
- </question>
- <answer>
-
- <para>You need to enable automatic flushing of the proxy's buffer as it receives
- packets. </para>
-
- <para>Most proxies, including mod_proxy, buffer data received from the server, and
- will not flush this data in real-time. Each proxy has an option to force
- flushing of each packet automatically, as this is necessary for streaming
- applications like Guacamole, but this is usually not enabled by default. </para>
-
- <para>Because Guacamole depends on streaming to function, a proxy configured to not
- automatically flush packets will disrupt the stream to the point that the
- connection seems unreasonably slow, or just fails to establish altogether. </para>
-
- <para>In the case of mod_proxy, this option is <code>flushpackets=on</code>. </para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>I connect to the internet through a web proxy, and cannot connect to
- Guacamole. I cannot reconfigure the proxy. How do I solve this? </para>
-
- </question>
- <answer>
-
- <para>You need to enable automatic flushing of your proxy's buffer to avoid
- disrupting the stream used by Guacamole. </para>
-
- <para>If you cannot change the settings of your proxy, using HTTPS instead of HTTP
- should solve the problem. Proxies are required to stream HTTPS because of the
- nature of SSL. Using HTTPS will allow Guacamole traffic to stream through
- proxies unencumbered, even if you cannot access the proxy settings directly. </para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>Can I buy special licensing of the Guacamole code base, such that I can use it
- in my own product, without providing the source to my users, without
- contributing back, and without acknowledging the project? </para>
-
- </question>
- <answer>
-
- <para>Usually, no. Previous requests for such licensing have been very one-sided and
- there would be no direct or indirect benefit to the community and the project.
- That said, we handle requests for licensing on a case-by-case basis. In general,
- any special licensing has to somehow provide for the community and the
- open-source project.</para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>Can I pay for custom Guacamole work, or for help integrating Guacamole into my
- product, if the open source nature and licenses are preserved?</para>
-
- </question>
- <answer>
-
- <para>Yes. We love to be paid to work on Guacamole, especially if that work remains
- open source. </para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>How can I contribute to the project? </para>
-
- </question>
- <answer>
-
- <para>If you are a programmer and want to contribute code, Guacamole is open-source
- and you are welcome to do so! Just send us your patches. There is no guarantee
- that your patch will be added to the upstream source, and all changes are
- carefully reviewed. </para>
-
- <para>If you are not a programmer, but want to help out, feel free to look through
- the documentation or try installing Guacamole and test it out. General editing,
- documentation contributions, and testing are always helpful. </para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>How can I become an official member of the project? </para>
-
- </question>
- <answer>
-
- <para>The short answer is: "by being asked." </para>
-
- <para>People are only added as official members of the Guacamole project after their
- work has been proven. This usually means you will have contributed code in the
- form of patches before, or we know you from extensive testing work, or you
- frequently help with documentation, and we are impressed enough that we want you
- as part of the project. </para>
-
- <para>All that said, you do not need to be a member of the project to help out. Feel
- free to contribute anything. </para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>I think I've found a bug. How do I report it? </para>
-
- </question>
- <answer>
-
- <para>The project tracks in-progress tasks and bugs via the JIRA instance hosted by
- the Apache Software Foundation:</para>
- <para><link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://issues.apache.org/jira/browse/GUACAMOLE/"
- ><uri>https://issues.apache.org/jira/browse/GUACAMOLE/</uri></link></para>
- <para>All bugs should be reported there as new issues. This is also where you would
- request a new feature. If the bug you found is security-related, we would prefer
- to be contacted personally via email, such that the bug can be fixed before
- becoming dangerously widely known. </para>
-
- </answer>
- </qandaentry>
-
- <qandaentry>
- <question>
-
- <para>I need help! Where can I find some? </para>
-
- </question>
- <answer>
-
- <para>If you would like help with Apache Guacamole, or wish to help others, we
- highly recommend sending an email to the one of the project’s <link
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="http://guacamole.apache.org/support/#mailing-lists"
- >mailing lists</link>. <emphasis>You will need to subscribe prior to sending
- email to any list.</emphasis> All mailing lists are actively filtered for
- spam, and any email not originating from a subscriber will bounce.</para>
- <para>There are two primary mailing lists:</para>
- <variablelist>
- <varlistentry>
- <term><link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="http://mail-archives.apache.org/mod_mbox/guacamole-user/"
- ><email>user@guacamole.apache.org</email></link></term>
- <listitem>
- <para>The user list is intended for general questions and discussions
- which do not necessarily pertain to development. This list replaces
- the old <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://sourceforge.net/p/guacamole/discussion/"
- >SourceForge forums</link> used by Guacamole prior to its
- acceptance into the Apache Software Foundation.</para>
- <para><emphasis>If you're not sure which mailing list to use, the user
- list is probably the correct choice.</emphasis></para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="http://mail-archives.apache.org/mod_mbox/guacamole-dev/"
- ><email>dev@guacamole.apache.org</email></link></term>
- <listitem>
- <para>The development list is for development-related discussion
- involving people who are contributors to the Apache Guacamole
- project (or who wish to become contributors).</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- </answer>
- </qandaentry>
-
- </qandaset>
-
-</appendix>
diff --git a/src/book.xslt b/src/book.xslt
deleted file mode 100644
index 095ae44..0000000
--- a/src/book.xslt
+++ /dev/null
@@ -1,144 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- Stylesheet for translating DocBook into XHTML -->
-<xsl:stylesheet
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:fo="http://www.w3.org/1999/XSL/Format"
- xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
- xmlns="http://docbook.org/ns/docbook"
- version="1.0">
-
- <xsl:import href="../docbook-xsl/fo/docbook.xsl"/>
-
-
- <!-- Book Dimensions -->
- <xsl:param name="page.width">7in</xsl:param>
- <xsl:param name="page.height">9.1875in</xsl:param>
-
- <!-- Margins (see
- https://www.createspace.com/Products/Book/InteriorPDF.jsp, as these
- dimensions are page-count-specific) -->
- <xsl:param name="page.margin.inner">1.25in</xsl:param>
- <xsl:param name="page.margin.outer">1.00in</xsl:param>
- <xsl:param name="page.margin.top">0.75in</xsl:param>
- <xsl:param name="page.margin.bottom">0.75in</xsl:param>
-
- <xsl:param name="double.sided">1</xsl:param>
- <xsl:param name="fop1.extensions" select="1"/>
-
- <xsl:param name="body.start.indent">0pt</xsl:param>
-
- <!-- Fonts -->
- <xsl:param name="title.font.family">Nimbus Sans L</xsl:param>
- <xsl:param name="body.font.family">Nimbus Roman No9 L</xsl:param>
- <xsl:param name="monospace.font.family">DejaVu Sans Mono</xsl:param>
-
- <!-- Limiting font-size of verbatim environments to 75% gives us
- at least 75 columns of text to work with, rather than way less
- than that. -->
- <xsl:attribute-set name="monospace.properties">
- <xsl:attribute name="font-size">
- <xsl:choose>
- <xsl:when test="
- local-name(..) = 'title'
- or local-name(..) = 'section'
- or local-name(..) = 'important'
- or local-name(..) = 'para'
- or local-name(..) = 'term'
- or local-name(..) = 'entry'
- or local-name(..) = 'emphasis'
- or local-name(.) = 'screen'
- or local-name(.) = 'programlisting'">0.75em</xsl:when>
- <xsl:otherwise>1em</xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:attribute-set>
-
- <!-- Require verbatim listings on same page -->
- <xsl:attribute-set name="monospace.verbatim.properties">
- <xsl:attribute name="keep-together.within-column">
- <xsl:choose>
- <xsl:when test="ancestor-or-self::*[@role='multipage']">auto</xsl:when>
- <xsl:otherwise>always</xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:attribute-set>
-
- <!-- Shade verbatim -->
- <xsl:param name="shade.verbatim" select="1"/>
-
- <xsl:attribute-set name="shade.verbatim.style">
- <xsl:attribute name="background-color">#E0E0E0</xsl:attribute>
- <xsl:attribute name="border-width">0.5pt</xsl:attribute>
- <xsl:attribute name="border-style">solid</xsl:attribute>
- <xsl:attribute name="border-color">#575757</xsl:attribute>
- <xsl:attribute name="padding">3pt</xsl:attribute>
- </xsl:attribute-set>
-
- <!-- We only want a book-level TOC -->
- <xsl:param name="generate.toc" select="'book toc'"/>
-
- <!-- No page breaks between reference entries -->
- <xsl:param name="refentry.pagebreak">0</xsl:param>
- <xsl:param name="refentry.generate.title">1</xsl:param>
- <xsl:param name="refentry.generate.name">0</xsl:param>
- <xsl:param name="funcsynopsis.style">ansi</xsl:param>
-
- <!-- Not draft mode -->
- <xsl:param name="draft.mode">no</xsl:param>
-
- <!-- Include admonition graphics -->
- <xsl:param name="admon.textlabel">0</xsl:param>
- <xsl:param name="admon.graphics">1</xsl:param>
- <xsl:param name="admon.graphics.path">images/</xsl:param>
- <xsl:param name="admon.graphics.extension">.png</xsl:param>
- <!--<xsl:attribute-set name="admonition.properties">
- <xsl:attribute name="border">2pt solid black</xsl:attribute>
- <xsl:attribute name="background-color">#CCCCCC</xsl:attribute>
- <xsl:attribute name="padding">0.1in</xsl:attribute>
- </xsl:attribute-set>-->
-
- <xsl:template match="*" mode="admon.graphic.width">
- <xsl:text>0.75in</xsl:text>
- </xsl:template>
-
- <!-- Chapter title page styling -->
- <xsl:attribute-set name="component.title.properties">
- <xsl:attribute name="border-bottom">1pt solid black</xsl:attribute>
- <xsl:attribute name="margin-bottom">0.5in</xsl:attribute>
- </xsl:attribute-set>
-
- <xsl:attribute-set name="component.label.properties">
- <xsl:attribute name="font-size">48pt</xsl:attribute>
- </xsl:attribute-set>
-
- <!-- Chapter title layout -->
- <xsl:template name="component.title">
- <xsl:param name="node" select="."/>
-
- <!-- CHAPTER + NUMBER -->
- <fo:block xsl:use-attribute-sets="component.label.properties">
- <xsl:if test="local-name(.)='title'">
- <xsl:call-template name="gentext">
- <xsl:with-param name="key">
- <xsl:value-of select="local-name(..)"/>
- </xsl:with-param>
- </xsl:call-template>
- <xsl:text> </xsl:text>
- </xsl:if>
- <xsl:apply-templates select="$node" mode="label.markup"/>
- </fo:block>
-
- <!-- TITLE -->
- <fo:block xsl:use-attribute-sets="component.title.properties">
- <xsl:apply-templates select="$node" mode="title.markup"/>
- </fo:block>
-
- </xsl:template>
-
- <!-- Center images -->
- <xsl:attribute-set name="informalfigure.properties">
- <xsl:attribute name="text-align">center</xsl:attribute>
- </xsl:attribute-set>
-
-</xsl:stylesheet>
diff --git a/src/cas-auth.md b/src/cas-auth.md
new file mode 100644
index 0000000..56d53c1
--- /dev/null
+++ b/src/cas-auth.md
@@ -0,0 +1,130 @@
+CAS Authentication
+==================
+
+CAS is an open-source Single Sign On (SSO) provider that allows multiple
+applications and services to authenticate against it and brokers those
+authentication requests to a back-end authentication provider. This module
+allows Guacamole to redirect to CAS for authentication and user services. This
+module must be layered on top of other authentication extensions that provide
+connection information, as it only provides user authentication.
+
+(cas-downloading)=
+
+Downloading the CAS authentication extension
+--------------------------------------------
+
+The CAS authentication extension is available separately from the main
+`guacamole.war`. The link for this and all other officially-supported and
+compatible extensions for a particular version of Guacamole are provided on the
+release notes for that version. You can find the release notes for current
+versions of Guacamole here: <http://guacamole.apache.org/releases/>.
+
+The CAS authentication extension is packaged as a `.tar.gz` file containing
+only the extension itself, `guacamole-auth-cas-1.3.0.jar`, which must
+ultimately be placed in `GUACAMOLE_HOME/extensions`.
+
+(installing-cas-auth)=
+
+Installing CAS authentication
+-----------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located within
+the `GUACAMOLE_HOME/extensions` directory. *If you are unsure where
+`GUACAMOLE_HOME` is located on your system, please consult
+[](configuring-guacamole) before proceeding.*
+
+To install the CAS authentication extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+ exist.
+
+2. Copy `guacamole-auth-cas-1.3.0.jar` within `GUACAMOLE_HOME/extensions`.
+
+3. Configure Guacamole to use CAS authentication, as described below.
+
+(guac-cas-config)=
+
+### Configuring Guacamole for CAS Authentication
+
+Guacamole's CAS support requires specifying two properties that describe the
+CAS authentication server and the Guacamole deployment. These properties are
+*absolutely required in all cases*, as they dictate how Guacamole should
+connect to the CAS and how CAS should redirect users back to Guacamole once
+their identity has been confirmed:
+
+`cas-authorization-endpoint`
+: The URL of the CAS authentication server. This should be the full path to the
+ base of the CAS installation.
+
+`cas-redirect-uri`
+: The URI to redirect back to upon successful authentication. Normally this
+ will be the full URL of your Guacamole installation.
+
+Additional optional properties are available to control how CAS tokens are
+processed, including whether [CAS ClearPass](cas-clearpass) should be used and
+how user group memberships should be derived:
+
+`cas-clearpass-key`
+: If using CAS ClearPass to pass the SSO password to Guacamole, this parameter
+ specifies the private key file to use to decrypt the password. See [the section
+ on ClearPass](cas-clearpass) below.
+
+`cas-group-attribute`
+: The CAS attribute that determines group membership, typically "memberOf".
+ This parameter is only required if using CAS to define user group memberships.
+ If omitted, groups aren't retrieved from CAS, and all other group-related
+ properties for CAS are ignored.
+
+`cas-group-format`
+: The format that CAS will use for its group names. Possible values are
+ `plain`, for groups that are simple text names, or `ldap`, for groups that are
+ represented as LDAP DNs. If set to `ldap`, group names are always determined
+ from the last (leftmost) attribute of the DN. If omitted, `plain` is used by
+ default.
+
+ This property has no effect if cas-group-attribute is not set.
+
+`cas-group-ldap-base-dn`
+: The base DN to require for LDAP-formatted CAS groups. If specified, only CAS
+ groups beneath this DN will be included, and all other CAS groups will be
+ ignored.
+
+ This property has no effect if cas-group-format is not `ldap`.
+
+`cas-group-ldap-attribute`
+: The LDAP attribute to require for LDAP-formatted CAS groups. If specified,
+ only CAS groups that use this attribute for the name of the group will be
+ included. Note that LDAP group names are *always determined from the last
+ (leftmost) attribute of the DN*. Specifying this property will only have the
+ effect of ignoring any groups that do not use the specified attribute to
+ represent the group name.
+
+ This property has no effect if cas-group-format is not `ldap`.
+
+(completing-cas-install)=
+
+### Completing the installation
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before CAS authentication can be used. *Doing this will disconnect all active
+users, so be sure that it is safe to do so prior to attempting installation.*
+When ready, restart your servlet container and give the new authentication a
+try.
+
+(cas-clearpass)=
+
+### Using CAS ClearPass
+
+CAS has a function called ClearPass that can be used to cache the password used
+for SSO authentication and make that available to services at a later time.
+Configuring the CAS server for ClearPass is beyond the scope of this article -
+more information can be found on the Apereo CAS wiki at the following URL:
+<https://apereo.github.io/cas>.
+
+Once you have CAS configured for credential caching, you need to configure the
+service with a keypair for passing the credential securely. The public key gets
+installed on the CAS server, while the private key gets configured with the
+cas-clearpass-key property. The private key file needs to be in RSA PKCS8
+format.
+
diff --git a/src/chapters/adding-protocol.xml b/src/chapters/adding-protocol.xml
deleted file mode 100644
index 3c92eef..0000000
--- a/src/chapters/adding-protocol.xml
+++ /dev/null
@@ -1,789 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="custom-protocols" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Adding new protocols</title>
- <indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>protocols</primary>
- <secondary>implementing</secondary>
- </indexterm>
- <para>Guacamole's support for multiple remote desktop protocols is provided through plugins
- which guacd loads dynamically. The Guacamole API has been designed such that protocol
- support is easy to create, especially when a C library exists providing a basic client
- implementation.</para>
- <para>In this tutorial, we will implement a simple "client" which renders a bouncing ball using
- the Guacamole protocol. After completing the tutorial and installing the result, you will be
- able to add a connection to your Guacamole configuration using the "ball" protocol, and any
- users using that connection will see a bouncing ball.</para>
- <para>This example client plugin doesn't actually act as a client, but this isn't important. The
- Guacamole client is really just a remote display, and this client plugin functions as a
- simple example application which renders to this display, just as Guacamole's own VNC or RDP
- plugins function as VNC or RDP clients which render to the remote display.</para>
- <para>Each step of this tutorial is intended to exercise a new concept,
- while also progressing towards the goal of a nifty bouncing ball. At the
- end of each step, you will have a buildable and working client
- plugin.</para>
- <para>This tutorial will use the GNU Automake build system, which is the build system used by
- Guacamole for libguac, guacd, etc. There will be four files involved:</para>
- <variablelist>
- <varlistentry>
- <term><filename>configure.ac</filename></term>
- <listitem>
- <para>Used by GNU Automake to generate the <filename>configure</filename> script
- which ultimately serves to generate the <filename>Makefile</filename> which
- <command>make</command> will use when building.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>Makefile.am</filename></term>
- <listitem>
- <para>Used by GNU Automake and the <filename>configure</filename> script to generate
- the <filename>Makefile</filename> which <command>make</command> will use when
- building.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>src/ball.c</filename></term>
- <listitem>
- <para>The main body of code defining the bouncing ball "client".</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>src/ball.h</filename></term>
- <listitem>
- <para>A header file defining the structure representing the state of the bouncing
- ball (once it becomes necessary to do so).</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>All source files will be within the <filename>src</filename> subdirectory, as is common
- with C projects, with build files being at the root level directory. The main
- <filename>src/ball.c</filename> and the build-related <filename>configure.ac</filename>
- and <filename>Makefile.am</filename> files will be created first, with each successive step
- building upon those files iteratively, with <filename>src/ball.h</filename> being added when
- it becomes necessary. After each step, you can build/rebuild the plugin by running
- <command>make</command>, and then install it (such that guacd can find the plugin) by
- running <command>make install</command> and <command>ldconfig</command> as root:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>make</userinput>
-<computeroutput> CC src/ball.lo
- CCLD libguac-client-ball.la</computeroutput>
-<prompt>#</prompt> <userinput>make install</userinput>
-<computeroutput>make[1]: Entering directory '/home/user/libguac-client-ball'
- /usr/bin/mkdir -p '/usr/local/lib'
- /bin/sh ./libtool --mode=install /usr/bin/install -c libguac-client-ball.la '/usr/local/lib'
-...
-----------------------------------------------------------------------
-Libraries have been installed in:
- /usr/local/lib
-
-If you ever happen to want to link against installed libraries
-in a given directory, LIBDIR, you must either use libtool, and
-specify the full pathname of the library, or use the '-LLIBDIR'
-flag during linking and do at least one of the following:
- - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable
- during execution
- - add LIBDIR to the 'LD_RUN_PATH' environment variable
- during linking
- - use the '-Wl,-rpath -Wl,LIBDIR' linker flag
- - have your system administrator add LIBDIR to '/etc/ld.so.conf'
-
-See any operating system documentation about shared libraries for
-more information, such as the ld(1) and ld.so(8) manual pages.
-----------------------------------------------------------------------
-make[1]: Nothing to be done for 'install-data-am'.
-make[1]: Leaving directory '/home/user/libguac-client-ball'</computeroutput>
-<prompt>#</prompt> <userinput>ldconfig</userinput></screen>
- </informalexample>
- <para>Prior to the first time <command>make</command> is invoked, you will need to run the
- <filename>configure</filename> script, which will first need to be generated using
- <command>autoreconf</command>:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>autoreconf -fi</userinput>
-<computeroutput>libtoolize: putting auxiliary files in '.'.
-libtoolize: copying file './ltmain.sh'
-libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
-libtoolize: copying file 'm4/libtool.m4'
-libtoolize: copying file 'm4/ltoptions.m4'
-libtoolize: copying file 'm4/ltsugar.m4'
-libtoolize: copying file 'm4/ltversion.m4'
-libtoolize: copying file 'm4/lt~obsolete.m4'
-configure.ac:10: installing './compile'
-configure.ac:4: installing './missing'
-Makefile.am: installing './depcomp'</computeroutput>
-<prompt>$</prompt> <userinput>./configure</userinput>
-<computeroutput>checking for a BSD-compatible install... /usr/bin/install -c
-checking whether build environment is sane... yes
-...
-configure: creating ./config.status
-config.status: creating Makefile
-config.status: executing depfiles commands
-config.status: executing libtool commands</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>This process is almost identical to that of building guacamole-server from git, as
- documented in <xref xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="building-guacamole-server"/>.</para>
- <important>
- <para>The libguac library which is part of guacamole-server is a required dependency of this
- project. <emphasis>You must first install libguac, guacd, etc. by <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="building-guacamole-server"
- >building and installing guacamole-server</link>.</emphasis> If guacamole-server
- has not been installed, and libguac is thus not present, the
- <filename>configure</filename> script will fail with an error indicating that it
- could not find libguac:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>./configure</userinput>
-<computeroutput>checking for a BSD-compatible install... /usr/bin/install -c
-checking whether build environment is sane... yes
-...
-checking for guac_client_stream_png in -lguac... no
-configure: error: "libguac is required for communication via "
- "the Guacamole protocol"</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>You will need to install guacamole-server and then rerun
- <filename>configure</filename>.</para>
- </important>
- <section xml:id="libguac-client-ball-skeleton">
- <title>Minimal skeleton client</title>
- <para>Very little needs too be done to implement the most basic client plugin possible. We
- begin with <filename>src/ball.c</filename>, containing the absolute minimum required for
- a client plugin:</para>
- <informalexample>
- <programlisting xml:id="ball-01-ball_client.c" version="5.0" xml:lang="en">#include <guacamole/client.h>
-
-#include <stdlib.h>
-
-/* Client plugin arguments (empty) */
-const char* TUTORIAL_ARGS[] = { NULL };
-
-int guac_client_init(guac_client* client) {
-
- /* This example does not implement any arguments */
- client->args = TUTORIAL_ARGS;
-
- return 0;
-
-}</programlisting>
- </informalexample>
- <para>Notice the structure of this file. There is exactly one function,
- <methodname>guac_client_init</methodname>, which is the entry
- point for all Guacamole client plugins. Just as a typical C program
- has a <methodname>main</methodname> function which is executed when
- the program is run, a Guacamole client plugin has
- <methodname>guac_client_init</methodname> which is called when
- guacd loads the plugin when a new connection is made and your
- protocol is selected.</para>
- <para><methodname>guac_client_init</methodname> receives a single
- <classname>guac_client</classname> which it must initialize. Part of this
- initialization process involves declaring the list of arguments that joining users can
- specify. While we won't be using arguments in this tutorial, and thus the arguments
- assigned above are simply an empty list, a typical client plugin implementation would
- register arguments which define the remote desktop connection and its behavior. Examples
- of such parameters can be seen in the connection parameters for the protocols supported
- by Guacamole out-of-the-box (see <xref xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="connection-configuration"/>).</para>
- <para>The <classname>guac_client</classname> instance given to
- <methodname>guac_client_init</methodname> will be shared by the user that starts the
- connection, and any users which join the connection via screen sharing. It lives until
- the connection is explicitly closed, or until all users leave the connection.</para>
- <para>For this project to build with GNU Automake, we a <filename>configure.ac</filename>
- file which describes the name of the project and what it needs configuration-wise. In
- this case, the project is "libguac-client-ball", and it depends on the "libguac" library
- used by guacd and all client plugins:</para>
- <informalexample>
- <programlisting xml:id="ball-01-configure.in" version="5.0" xml:lang="en"># Project information
-AC_PREREQ([2.61])
-AC_INIT([libguac-client-ball], [0.1.0])
-AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
-AM_SILENT_RULES([yes])
-
-AC_CONFIG_MACRO_DIRS([m4])
-
-# Check for required build tools
-AC_PROG_CC
-AC_PROG_CC_C99
-AC_PROG_LIBTOOL
-
-# Check for libguac
-AC_CHECK_LIB([guac], [guac_client_stream_png],,
- AC_MSG_ERROR("libguac is required for communication via "
- "the Guacamole protocol"))
-
-AC_CONFIG_FILES([Makefile])
-AC_OUTPUT</programlisting></informalexample>
- <para>We also need a <filename>Makefile.am</filename>, describing which files should be
- built and how when building
- libguac-client-ball:<programlisting xml:id="ball-01-Makefile.am" version="5.0" xml:lang="en">AUTOMAKE_OPTIONS = foreign
-
-ACLOCAL_AMFLAGS = -I m4
-AM_CFLAGS = -Werror -Wall -pedantic
-
-lib_LTLIBRARIES = libguac-client-ball.la
-
-# All source files of libguac-client-ball
-libguac_client_ball_la_SOURCES = src/ball.c
-
-# libtool versioning information
-libguac_client_ball_la_LDFLAGS = -version-info 0:0:0</programlisting></para>
- <para>The GNU Automake files will remain largely unchanged throughout
- the rest of the tutorial. </para>
- <para>Once you have created all of the above files, you will have a functioning client
- plugin. It doesn't do anything yet, and any connection will be extremely short-lived
- (the lack of any data sent by the server will lead to the client disconnecting under the
- assumption that the connection has stopped responding), but it does technically
- work.</para>
- </section>
- <section xml:id="libguac-client-ball-display-init">
- <title>Initializing the remote display</title>
- <para>Now that we have a basic functioning skeleton, we need to actually do something with
- the remote display. A good first step would be simply initializing the display - setting
- the remote display size and providing a basic background.</para>
- <para>In this case, we'll set the display to a nice default of 1024x768, and fill the
- background with gray. Though the size of the display <emphasis>can</emphasis> be chosen
- based on the size of the user's browser window (which is provided by the user during the
- <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-protocol-handshake">Guacamole protocol handshake</link>), or even
- updated when the window size changes (provided by the user via <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="size-event-instruction">"size"
- instructions</link>), we won't be doing that here for the simplicity's sake:</para>
- <informalexample>
- <programlisting xml:id="ball-02-ball_client.c" version="5.0" xml:lang="en">#include <guacamole/client.h>
-<emphasis>#include <guacamole/protocol.h>
-#include <guacamole/socket.h>
-#include <guacamole/user.h></emphasis>
-
-#include <stdlib.h>
-
-...
-
-<emphasis>int ball_join_handler(guac_user* user, int argc, char** argv) {
-
- /* Get client associated with user */
- guac_client* client = user->client;
-
- /* Get user-specific socket */
- guac_socket* socket = user->socket;
-
- /* Send the display size */
- guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, 1024, 768);
-
- /* Prepare a curve which covers the entire layer */
- guac_protocol_send_rect(socket, GUAC_DEFAULT_LAYER,
- 0, 0, 1024, 768);
-
- /* Fill curve with solid color */
- guac_protocol_send_cfill(socket,
- GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
- 0x80, 0x80, 0x80, 0xFF);
-
- /* Mark end-of-frame */
- guac_protocol_send_sync(socket, client->last_sent_timestamp);
-
- /* Flush buffer */
- guac_socket_flush(socket);
-
- /* User successfully initialized */
- return 0;
-
-}</emphasis>
-
-int guac_client_init(guac_client* client) {
-
- /* This example does not implement any arguments */
- client->args = TUTORIAL_ARGS;
-<emphasis>
- /* Client-level handlers */
- client->join_handler = ball_join_handler;
-</emphasis>
- return 0;
-
-}</programlisting></informalexample>
- <para>The most important thing to notice here is the new
- <function>ball_join_handler()</function> function. As it is assigned to
- <property>join_handler</property> of the <classname>guac_client</classname> given to
- <function>guac_client_init</function>, users which join the connection (including
- the user that opened the connection in the first place) will be passed to this function.
- It is the duty of the join handler to initialize the provided
- <classname>guac_user</classname>, taking into account any arguments received from
- the user during the connection handshake (exposed through <varname>argc</varname> and
- <varname>argv</varname> to the join handler). We aren't implementing any arguments,
- so these values are simply ignored, but we do need to initialize the user with respect
- to display state. In this case, we:</para>
- <orderedlist>
- <listitem>
- <para>Send a <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="size-instruction">"size" instruction</link>, initializing the
- display size to 1024x768.</para>
- </listitem>
- <listitem>
- <para>Draw a 1024x768 gray rectangle over the display using the <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="rect-instruction"
- >"rect"</link> and <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="cfill-instruction">"cfill"</link> instructions.</para>
- </listitem>
- <listitem>
- <para>Send a <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="server-sync-instruction">"sync" instruction</link>, informing the
- remote display that a frame has been completed.</para>
- </listitem>
- <listitem>
- <para>Flush the socket, ensuring that all data written to the socket thus far is
- immediately sent to the user.</para>
- </listitem>
- </orderedlist>
- <para>At this point, if you build, install, and connect using the plugin, you will see a
- gray screen. The connection will still be extremely short-lived, however, since the only
- data ever sent by the plugin is sent when the user first joins. The lack of any data
- sent by the server over the remaining life of the connection will lead to the client
- disconnecting under the assumption that the connection has stopped responding. This will
- be rectified shortly once we add the bouncing ball.</para>
- </section>
- <section xml:id="libguac-client-ball-layer">
- <title>Adding the ball</title>
- <para>This tutorial is about making a bouncing ball "client", so naturally we need a ball to
- bounce. While we could repeatedly draw and erase a ball on the remote display, a more
- efficient technique would be to leverage Guacamole's layers.</para>
- <para>The remote display has a single root layer, <varname>GUAC_DEFAULT_LAYER</varname>, but
- there can be infinitely many other child layers, which can themselves have child layers,
- and so on. Each layer can be dynamically repositioned within and relative to another
- layer. Because the compositing of these layers is handled by the remote display, and is
- likely hardware-accelerated, this is a much better way to repeatedly reposition
- something we expect to move a lot.</para>
- <para>Since we're finally adding the ball, and there needs to be some structure which
- maintains the state of the ball, we must create a header file,
- <filename>src/ball.h</filename>, to define this:</para>
- <informalexample>
- <programlisting version="5.0" xml:lang="en">#ifndef BALL_H
-#define BALL_H
-
-#include <guacamole/layer.h>
-
-typedef struct ball_client_data {
-
- guac_layer* ball;
-
-} ball_client_data;
-
-#endif</programlisting>
- </informalexample>
- <para>To make the build system aware of the existence of the new
- <filename>src/ball.h</filename> header file, <filename>Makefile.am</filename> must
- be updated as well:</para>
- <informalexample>
- <programlisting version="5.0" xml:lang="en">...
-
-# All source files of libguac-client-ball
-<emphasis>noinst_HEADERS = src/ball.h</emphasis>
-libguac_client_ball_la_SOURCES = src/ball.c
-
-...</programlisting>
- </informalexample>
- <para>This new structure is intended to house the client-level state of the ball,
- independent of any users which join or leave the connection. The structure must be
- allocated when the client begins (within <function>guac_client_init</function>), freed
- when the client terminates (via a new client free handler), and must contain the layer
- which represents the ball within the remote display. As this layer is part of the remote
- display state, it must additionally be initialized when a user joins, in the same way
- that the display overall was initialized in earlier steps:</para>
- <informalexample>
- <programlisting xml:id="ball-03-ball_client.c" version="5.0" xml:lang="en"><emphasis>#include "ball.h"</emphasis>
-
-#include <guacamole/client.h>
-<emphasis>#include <guacamole/layer.h></emphasis>
-#include <guacamole/protocol.h>
-#include <guacamole/socket.h>
-#include <guacamole/user.h>
-
-#include <stdlib.h>
-
-...
-
-int ball_join_handler(guac_user* user, int argc, char** argv) {
-
- /* Get client associated with user */
- guac_client* client = user->client;
-<emphasis>
- /* Get ball layer from client data */
- ball_client_data* data = (ball_client_data*) client->data;
- guac_layer* ball = data->ball;
-</emphasis>
- ...
-<emphasis>
- /* Set up ball layer */
- guac_protocol_send_size(socket, ball, 128, 128);
-
- /* Prepare a curve which covers the entire layer */
- guac_protocol_send_rect(socket, ball,
- 0, 0, 128, 128);
-
- /* Fill curve with solid color */
- guac_protocol_send_cfill(socket,
- GUAC_COMP_OVER, ball,
- 0x00, 0x80, 0x80, 0xFF);
-</emphasis>
- /* Mark end-of-frame */
- guac_protocol_send_sync(socket, client->last_sent_timestamp);
-
- /* Flush buffer */
- guac_socket_flush(socket);
-
- /* User successfully initialized */
- return 0;
-
-}
-
-<emphasis>int ball_free_handler(guac_client* client) {
-
- ball_client_data* data = (ball_client_data*) client->data;
-
- /* Free client-level ball layer */
- guac_client_free_layer(client, data->ball);
-
- /* Free client-specific data */
- free(data);
-
- /* Data successfully freed */
- return 0;
-
-}</emphasis>
-
-int guac_client_init(guac_client* client) {
-<emphasis>
- /* Allocate storage for client-specific data */
- ball_client_data* data = malloc(sizeof(ball_client_data));
-
- /* Set up client data and handlers */
- client->data = data;
-
- /* Allocate layer at the client level */
- data->ball = guac_client_alloc_layer(client);
-</emphasis>
- ...
-
- /* Client-level handlers */
- client->join_handler = ball_join_handler;
- <emphasis>client->free_handler = ball_free_handler;</emphasis>
-
- return 0;
-
-}</programlisting></informalexample>
- <para>The allocate/free pattern for the client-specific data and layers should be pretty
- straightforward - the allocation occurs when the objects (the layer and the structure
- housing it) are first needed, and the allocated objects are freed once they are no
- longer needed (when the client terminates) to avoid leaking memory. The initialization
- of the ball layer using the Guacamole protocol should be familiar as well - it's
- identical to the way the screen was initialized, and involves the same
- instructions.</para>
- <para>Beyond layers, Guacamole has the concept of buffers, which are identical in use to
- layers except they are invisible. Buffers are used to store image data for the sake of
- caching or drawing operations. We will use them later when we try to make this tutorial
- prettier. If you build and install the ball client as-is now, you will see a large gray
- rectangle (the root layer) with a small blue square in the upper left corner (the ball
- layer).</para>
- </section>
- <section xml:id="libguac-client-ball-bounce">
- <title>Making the ball bounce</title>
- <para>To make the ball bounce, we need to track the ball's state, including current position
- and velocity, as well as a thread which updates the ball's state (and the remote
- display) as time progresses. The ball state and thread can be stored alongside the ball
- layer in the existing client-level data structure:</para>
- <informalexample>
- <programlisting xml:id="ball-04-ball_client.h" version="5.0" xml:lang="en">...
-
-#include <guacamole/layer.h>
-
-<emphasis>#include <pthread.h></emphasis>
-
-typedef struct ball_client_data {
-
- guac_layer* ball;
-<emphasis>
- int ball_x;
- int ball_y;
-
- int ball_velocity_x;
- int ball_velocity_y;
-
- pthread_t render_thread;
-</emphasis>
-} ball_client_data;
-
-...</programlisting></informalexample>
- <para>The contents of the thread will update these values at a pre-defined rate, changing
- ball position with respect to velocity, and changing velocity with respect to collisions
- with the display boundaries:</para>
- <informalexample>
- <programlisting version="5.0" xml:lang="en">#include "ball.h"
-
-#include <guacamole/client.h>
-#include <guacamole/layer.h>
-#include <guacamole/protocol.h>
-#include <guacamole/socket.h>
-#include <guacamole/user.h>
-
-<emphasis>#include <pthread.h></emphasis>
-#include <stdlib.h>
-
-...
-
-<emphasis>void* ball_render_thread(void* arg) {
-
- /* Get data */
- guac_client* client = (guac_client*) arg;
- ball_client_data* data = (ball_client_data*) client->data;
-
- /* Update ball position as long as client is running */
- while (client->state == GUAC_CLIENT_RUNNING) {
-
- /* Sleep a bit */
- usleep(30000);
-
- /* Update position */
- data->ball_x += data->ball_velocity_x * 30 / 1000;
- data->ball_y += data->ball_velocity_y * 30 / 1000;
-
- /* Bounce if necessary */
- if (data->ball_x < 0) {
- data->ball_x = -data->ball_x;
- data->ball_velocity_x = -data->ball_velocity_x;
- }
- else if (data->ball_x >= 1024 - 128) {
- data->ball_x = (2 * (1024 - 128)) - data->ball_x;
- data->ball_velocity_x = -data->ball_velocity_x;
- }
-
- if (data->ball_y < 0) {
- data->ball_y = -data->ball_y;
- data->ball_velocity_y = -data->ball_velocity_y;
- }
- else if (data->ball_y >= 768 - 128) {
- data->ball_y = (2 * (768 - 128)) - data->ball_y;
- data->ball_velocity_y = -data->ball_velocity_y;
- }
-
- guac_protocol_send_move(client->socket, data->ball,
- GUAC_DEFAULT_LAYER, data->ball_x, data->ball_y, 0);
-
- /* End frame and flush socket */
- guac_client_end_frame(client);
- guac_socket_flush(client->socket);
-
- }
-
- return NULL;
-
-}</emphasis>
-
-...</programlisting></informalexample>
- <para>Just as with the join handler, this thread sends a "sync" instruction to denote the
- end of each frame, though here this is accomplished with
- <function>guac_client_end_frame()</function>. This function sends a "sync"
- containing the current timestamp, and updates the properties of the
- <classname>guac_client</classname> with the last-sent timestamp (the value that our
- join handler uses to send <emphasis>its</emphasis> sync). Note that we don't redraw the
- whole display with each frame - we simply update the position of the ball layer using a
- <link xmlns:xlink="http://www.w3.org/1999/xlink" linkend="move-instruction">"move"
- instruction</link>, and rely on the remote display to handle compositing on its
- own.</para>
- <para>We now need to update <methodname>guac_client_init</methodname> to actually create
- this thread, initialize the ball state within the structure, and store the thread for
- future cleanup when the client terminates:</para>
- <informalexample>
- <programlisting xml:id="ball-04-ball_client.c" version="5.0" xml:lang="en">...
-
-int ball_free_handler(guac_client* client) {
-
- ball_client_data* data = (ball_client_data*) client->data;
-<emphasis>
- /* Wait for render thread to terminate */
- pthread_join(data->render_thread, NULL);
-</emphasis>
- ...
-
-}
-
-int guac_client_init(guac_client* client) {
-
- ...
-<emphasis>
- /* Start ball at upper left */
- data->ball_x = 0;
- data->ball_y = 0;
-
- /* Move at a reasonable pace to the lower right */
- data->ball_velocity_x = 200; /* pixels per second */
- data->ball_velocity_y = 200; /* pixels per second */
-
- /* Start render thread */
- pthread_create(&data->render_thread, NULL, ball_render_thread, client);
-</emphasis>
- ...
-
-}</programlisting></informalexample>
- <para>The thread contains a render loop which continually checks the
- <property>state</property> property of the <classname>guac_client</classname>. This
- property is set to <constant>GUAC_CLIENT_RUNNING</constant> when the connection begins,
- and remains that way for the duration of the connection. When guacd needs to terminate
- the connection (such as when the last user leaves), the value will change to
- <constant>GUAC_CLIENT_STOPPING</constant>. The free handler we've written can thus
- rely on <function>pthread_join()</function> to block until the data previously used by
- the plugin is no longer being used and can safely be freed.</para>
- <para>Once built and installed, our ball client now has a bouncing ball, albeit a very
- square and plain one. Now that the display is continually updating, and data is being
- continually received from the server, connected clients will no longer automatically
- disconnect.</para>
- </section>
- <section xml:id="libguac-client-ball-pretty">
- <title>A prettier ball</title>
- <para>Now that we have our ball bouncing, we might as well try to make it actually look like
- a ball, and try applying some of the fancier graphics features that Guacamole offers.
- Guacamole provides instructions common to most 2D drawing APIs, including HTML5's canvas
- and Cairo. This means you can draw arcs, curves, apply fill and stroke, and even use the
- contents of another layer or buffer as the pattern for a fill or stroke. In complex
- cases involving many draw operations, it will actually be more efficient to render to a
- server-side Cairo surface and send only image data to the client, but it's perfect for
- relatively simple cases like our ball.</para>
- <para>We will try creating a simple gray checkerboard pattern in a buffer, using that for
- the background instead of the previous gray rectangle, and will modify the ball by
- replacing the rectangle with an arc, in this case a full circle, complete with stroke
- (border) and translucent-blue fill:</para>
- <informalexample>
- <programlisting xml:id="ball-05-ball_client.c" version="5.0" xml:lang="en">int ball_join_handler(guac_user* user, int argc, char** argv) {
-
- ...
-<emphasis>
- /* Create background tile */
- guac_layer* texture = guac_client_alloc_buffer(client);
-
- guac_protocol_send_rect(socket, texture, 0, 0, 64, 64);
- guac_protocol_send_cfill(socket, GUAC_COMP_OVER, texture,
- 0x88, 0x88, 0x88, 0xFF);
-
- guac_protocol_send_rect(socket, texture, 0, 0, 32, 32);
- guac_protocol_send_cfill(socket, GUAC_COMP_OVER, texture,
- 0xDD, 0xDD, 0xDD, 0xFF);
-
- guac_protocol_send_rect(socket, texture, 32, 32, 32, 32);
- guac_protocol_send_cfill(socket, GUAC_COMP_OVER, texture,
- 0xDD, 0xDD, 0xDD, 0xFF);
-</emphasis>
-
- /* Prepare a curve which covers the entire layer */
- guac_protocol_send_rect(socket, GUAC_DEFAULT_LAYER,
- 0, 0, 1024, 768);
-
- /* Fill curve with <emphasis>texture</emphasis> */
- <emphasis>guac_protocol_send_lfill</emphasis>(socket,
- GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
- <emphasis>texture</emphasis>);
-
- /* Set up ball layer */
- guac_protocol_send_size(socket, ball, 128, 128);
-<emphasis>
- /* Prepare a circular curve */
- guac_protocol_send_arc(socket, data->ball,
- 64, 64, 62, 0, 6.28, 0);
-
- guac_protocol_send_close(socket, data->ball);
-
- /* Draw a 4-pixel black border */
- guac_protocol_send_cstroke(socket,
- GUAC_COMP_OVER, data->ball,
- GUAC_LINE_CAP_ROUND, GUAC_LINE_JOIN_ROUND, 4,
- 0x00, 0x00, 0x00, 0xFF);
-
- /* Fill the circle with color */
- guac_protocol_send_cfill(socket,
- GUAC_COMP_OVER, data->ball,
- 0x00, 0x80, 0x80, 0x80);
-
- /* Free texture (no longer needed) */
- guac_client_free_buffer(client, texture);
-</emphasis>
- /* Mark end-of-frame */
- guac_protocol_send_sync(socket, client->last_sent_timestamp);
-
- ...
-
-}</programlisting></informalexample>
- <para>Again, because we put the ball in its own layer, we don't have to worry about
- compositing it ourselves. The remote display will handle this, and will likely do so
- with hardware acceleration, even though the ball is now translucent. Build and install
- the ball client after this step, and you will have a rather nice-looking bouncing
- ball.</para>
- </section>
- <section xml:id="libguac-client-ball-time">
- <title>Handling the passage of time</title>
- <para>There are never any guarantees when it comes to timing, threads, and network
- performance. We cannot necessarily rely on the remote display to handle updates in a
- timely manner (it may be slow), nor can we rely on the network or server to give
- priority to communication from guacd. </para>
- <para>The render thread needs to be modified to take this into account, by tracking the
- actual time spent within each frame, and estimating the amount of time the client spends
- rendering each frame:</para>
- <informalexample>
- <programlisting version="5.0" xml:lang="en">#include "ball.h"
-
-#include <guacamole/client.h>
-#include <guacamole/layer.h>
-#include <guacamole/protocol.h>
-#include <guacamole/socket.h>
-<emphasis>#include <guacamole/timestamp.h></emphasis>
-#include <guacamole/user.h>
-
-#include <pthread.h>
-#include <stdlib.h>
-
-...
-
-void* ball_render_thread(void* arg) {
-
- ...
-<emphasis>
- /* Init time of last frame to current time */
- guac_timestamp last_frame = guac_timestamp_current();
-</emphasis>
- /* Update ball position as long as client is running */
- while (client->state == CLIENT_RUNNING) {
-<emphasis>
- /* Default to 30ms frames */
- int frame_duration = 30;
-
- /* Lengthen frame duration if client is lagging */
- int processing_lag = guac_client_get_processing_lag(client);
- if (processing_lag > frame_duration)
- frame_duration = processing_lag;
-
- /* Sleep for duration of frame, then get timestamp */
- usleep(frame_duration);
- guac_timestamp current = guac_timestamp_current();
-
- /* Calculate change in time */
- int delta_t = current - last_frame;
-</emphasis>
- /* Update position */
- data->ball_x += data->ball_velocity_x * <emphasis>delta_t</emphasis> / 1000;
- data->ball_y += data->ball_velocity_y * <emphasis>delta_t</emphasis> / 1000;
-
- ...
-<emphasis>
- /* Update timestamp */
- last_frame = current;
-</emphasis>
- }
-
- ...
-
-}</programlisting></informalexample>
- <para>The calculations are pretty simple. Rather than hard-code the duration of each frame,
- we us a default of 30 milliseconds, lengthening the frame if Guacamole's built-in lag
- estimation determines that the client is having trouble. The physics portion of the
- update no longer assumes that the frame will be exactly 30 milliseconds, instead relying
- on the actual time elapsed since the previous frame.</para>
- <para>At this point, we now have a robust Guacamole client plugin. It handles
- joining/leaving users correctly, continually updates the remote display state while
- taking into account variable network/server/client conditions, and cleans up after
- itself when the connection finally terminates.</para>
- </section>
-</chapter>
diff --git a/src/chapters/adhoc-connections.xml b/src/chapters/adhoc-connections.xml
deleted file mode 100644
index 861c754..0000000
--- a/src/chapters/adhoc-connections.xml
+++ /dev/null
@@ -1,171 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="adhoc-connections" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>Ad-hoc Connections</title>
- <indexterm>
- <primary>connections</primary>
- <secondary>adhoc</secondary>
- </indexterm>
- <indexterm>
- <primary>adhoc</primary>
- </indexterm>
- <indexterm>
- <primary>quickconnect</primary>
- </indexterm>
- <para>The quickconnect extension provides a connection bar on the Guacamole Client home page
- that allows users to type in the URI of a server to which they want to connect and the client
- will parse the URI and immediately establish the connection. The purpose of the extension is
- to allow situations where administrators want to allow users the flexibility of establishing
- their own connections without having to grant them access to edit connections or even to have
- to create the connections at all, aside from typing the URI.</para>
- <important>
- <para>There are several implications of using this extension that should be well-understood
- by administrators prior to implementing it:</para>
- <itemizedlist>
- <listitem><para>Connections established with this extension are created in-memory
- and only persist until the Guacamole session ends.</para></listitem>
- <listitem><para>Connections created with this extension are not accessible to other users, and
- cannot be shared with other users.</para></listitem>
- <listitem><para>This extension provides no functionality for authenticating users - it does
- not allow anonymous logins, and requires that users are successfully authenticated
- by another authentication module before it can be used.</para></listitem>
- <listitem><para>The extension provides users the ability not only to establish connections, but
- also to set any of the parameters for a connection. There are security implications for
- this - for example, RDP file sharing can be used to pass through any directory available
- on the server running guacd to the remote desktop. This should be taken into consideration
- when enabling this extension and making sure that guacd is configured in a way that
- does not compromise sensitive system files by allowing access to them.</para></listitem>
- </itemizedlist>
- </important>
- <section xml:id="quickconnect-downloading">
- <title>Downloading the quickconnect extension</title>
- <para>The quickconnect extension is available separately from the main
- <filename>guacamole.war</filename>. The link for this and all other
- officially-supported and compatible extensions for a particular version of Guacamole are
- provided in the release notes for that version. You can find the release notes for
- current versions of Guacamole here: <link
- xlink:href="http://guacamole.apache.org/releases/"
- >http://guacamole.apache.org/releases/</link>.</para>
- <para>The quickconnect extension is packaged as a <filename>.tar.gz</filename> file containing
- only the extension itself, <filename>guacamole-auth-quickconnect-1.3.0.jar</filename>, which must
- ultimately be placed in <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </section>
- <section xml:id="installing-quickconnect">
- <title>Installing the quickconnect extension</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- located within the <filename>GUACAMOLE_HOME/extensions</filename> directory.
- <emphasis>If you are unsure where <varname>GUACAMOLE_HOME</varname> is located on
- your system, please consult <xref linkend="configuring-guacamole"/> before
- proceeding.</emphasis></para>
- <para>To install the extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Place the <filename>guacamole-auth-quickconnect-1.3.0.jar</filename> file in
- the <filename>GUACAMOLE_HOME/extensions</filename> directory.</para>
- </step>
- </procedure>
- <section xml:id="guac-quickconnect-config">
- <title>Configuring Guacamole for the quickconnect extension</title>
- <indexterm>
- <primary>configuring quickconnect</primary>
- </indexterm>
- <para>The quickconnect extension has two configuration properties that
- allow for controlling what connection parameters can be used
- in the URIs that are opened with the quickconnect extension:</para>
- <variablelist>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>quickconnect-allowed-parameters</primary>
- </indexterm><parameter>quickconnect-allowed-parameters</parameter></term>
- <listitem>
- <para>An optional list of parameters that are allowed to be
- used by connections that are created and accessed via
- the quickconnect extension. If this property is present,
- only parameters in this list will be allowed. If this
- property is absent, any/all parameters will be allowed
- unless explicitly denied using the
- <parameter>quickconnect-denied-parameters</parameter>
- property.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>quickconnect-denied-parameters</primary>
- </indexterm><parameter>quickconnect-denied-parameters</parameter></term>
- <listitem>
- <para>An optional list of parameters that are explicitly
- denied from being used by connections created and
- accessed via the quickconnect extension. If this
- property is present, any parameters in this list will
- be removed from the connection configuration when it is
- created, <emphasis>even if those parameter are listed
- above in the <parameter>quickconnect-allowed-parameters</parameter>
- property.</emphasis>
- If this property is not present, no connection parameters
- will be explicitly denied.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="completing-quickconnect-install">
- <title>Completing the installation</title>
- <para>Guacamole will only load newly-installed extensions during startup, so your
- servlet container will need to be restarted before the quickconnect extension
- can be used. <emphasis>Doing this will disconnect all active users, so be sure
- that it is safe to do so prior to attempting installation.</emphasis>
- When ready, restart your servlet container and give the extension a try.</para>
- </section>
- </section>
- <section xml:id="using-quickconnect">
- <title>Using the quickconnect extension</title>
- <para>The quickconnect extension provides a field on the home page that allows you to enter
- a Uniform Resource Identifier (URI) to create a connection. A URI is in the form:</para>
- <informalexample>
- <para><uri><replaceable>protocol</replaceable>://<replaceable>username</replaceable>:<replaceable>password</replaceable>@<replaceable>host</replaceable>:<replaceable>port</replaceable>/?<replaceable>parameters</replaceable></uri></para>
- </informalexample>
- <para>The <replaceable>protocol</replaceable> field can have any of the protocols supported
- by Guacamole, as documented in <xref linkend="configuring-guacamole"/>. Many of the
- protocols define a default <replaceable>port</replaceable> value, with the exception of
- VNC. The <replaceable>parameters</replaceable> field can specify any of the
- protocol-specific parameters as documented on the configuration page.</para>
- <para>To establish a connection, simply type in a valid URI and either press "Enter" or
- click the connect button. This extension will parse the URI and create a new connection,
- and immediately start that connection in the current browser.</para>
- <para>Here are a few examples of URIs:</para>
- <itemizedlist>
- <listitem>
- <informalexample>
- <para><uri>ssh://linux1.example.com/</uri></para>
- </informalexample>
- <para>Connect to the server linux1.example.com using the SSH protocol on the default
- SSH port (22). This will result in prompting for both username and
- password.</para>
- </listitem>
- <listitem>
- <informalexample>
- <para><uri>vnc://linux1.example.com:5900/</uri></para>
- </informalexample>
- <para>Connect to the server linux1.example.com using the VNC protocol and specifying
- the port as 5900.</para>
- </listitem>
- <listitem>
- <informalexample>
- <para><uri>
- rdp://localuser@windows1.example.com/?security=rdp&ignore-cert=true&disable-audio=true&enable-drive=true&drive-path=/mnt/usb
- </uri></para>
- </informalexample>
- <para>Connect to the server windows1.example.com using the RDP protocol and the user
- "localuser". This URI also specifies several RDP-specific parameters on the
- connection, including forcing security mode to RDP (security=rdp), ignoring any
- certificate errors (ignore-cert=true), disabling audio pass-through
- (disable-audio=true), and enabling filesystem redirection (enable-drive=true) to
- the /mnt/usb folder on the system running guacd (drive-path=/mnt/usb).</para>
- </listitem>
- </itemizedlist>
- </section>
-</chapter>
diff --git a/src/chapters/administration.xml b/src/chapters/administration.xml
deleted file mode 100644
index e33f735..0000000
--- a/src/chapters/administration.xml
+++ /dev/null
@@ -1,453 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="administration" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Administration</title>
- <indexterm>
- <primary>administration</primary>
- </indexterm>
- <para>Users, user groups, connections, and active sessions can be administered from within the
- web interface if the underlying authentication module supports this. The only
- officially-supported authentication modules supporting this are the database extensions,
- which are documented in <xref linkend="jdbc-auth"/>.</para>
- <para>If you are using the default authentication mechanism, or another authentication
- extension, this chapter probably does not apply to you, and the management options will not
- be visible in the Guacamole interface. If, on the other hand, you are using one of the
- database authentication providers, and you are logged in as a user with sufficient
- privileges, you will see management sections listed within the settings screen:</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guacamole-settings-sections.png" format="PNG"
- contentwidth="3.5in"/>
- </imageobject>
- <caption>
- <para>Sections within the Guacamole settings screen.</para>
- </caption>
- </mediaobject>
- </informalfigure>
- <para>Clicking any of these options will take you to a corresponding management section where
- you can perform administrative tasks.</para>
- <section xml:id="session-management">
- <title>Managing sessions</title>
- <indexterm>
- <primary>session management</primary>
- </indexterm>
- <para>Clicking "Active Sessions" navigates to the session management screen. The session
- management screen displays all active sessions and allows system administrators to kill
- them as needed.</para>
- <para>When any user accesses a particular remote desktop connection, a unique session is
- created and will appear in the list of active sessions in the session management screen.
- Each active session is displayed in a sortable table, showing the corresponding user's
- username, how long the session has been active, the IP address of the machine from which
- the user is connecting, and the name of the connection being used.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/manage-sessions.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Session management interface</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <para>To kill one or more sessions, select the sessions by clicking their checkboxes. Once
- all desired sessions have been selected, clicking "Kill Sessions" will immediately
- disconnect those users from the associated connection.</para>
- <section xml:id="filtering-sessions">
- <title>Filtering and sorting</title>
- <para>The table can be resorted by clicking on the column headers. Clicking any column
- will resort the table by the values within that column, while clicking a column
- which is already sorted will toggle between ascending and descending order.</para>
- <para>The content of the table can be limited through search terms specified in the
- "Filter" field. Entering search terms will limit the table to only sessions
- containing those terms. For example, to list only connections by the user
- "guacadmin" which have been active since March, 2015, you would enter: "guacadmin
- 2015-03". Beware that if a search term needs to contain spaces, it must be enclosed
- in double quotes to avoid being interpreted as multiple terms.</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/session-filter-example-1.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- <para>If you wish to narrow the content of the table to only those connections which
- originate from a particular block of IP addresses, you can do this by specifying the
- block in standard CIDR notation, such "10.0.0.0/8" or "2001:db8:1234::/48". This
- will work with both IPv4 and IPv6 addresses.</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/session-filter-example-2.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
- </section>
- <section xml:id="connection-history">
- <title>Connection history</title>
- <indexterm>
- <primary>history</primary>
- </indexterm>
- <indexterm>
- <primary>connection history</primary>
- </indexterm>
- <para>Clicking "History" navigates to the connection history screen. The connection history
- screen displays a table of the most recent connections, including the user that used
- that connection, the time the connection began, and how long the connection was
- used.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/manage-history.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Connection history interface</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <section xml:id="filtering-history">
- <title>Filtering and sorting</title>
- <para>Initially, the connection history table will display only the most recent history
- records. You can page through these records to see how and when Guacamole has been
- used.</para>
- <para>Just as with the table of active sessions described earlier, the table of history
- records can be resorted by clicking on the column headers or filtered by entering
- search terms within the "Filter" field.</para>
- <para>The same filtering format applies - a search term containing spaces must be
- enclosed in double quotes to avoid being interpreted as multiple terms, and only
- history records which contain each term will be included in the history table.
- Unlike the table of active sessions, however, the filter will only take effect once
- you click the "Search" button. This is due to the nature of the connection history,
- as the number of records may be quite extensive.</para>
- </section>
- </section>
- <section xml:id="user-management">
- <title>User management</title>
- <indexterm>
- <primary>user management</primary>
- </indexterm>
- <para>Clicking "Users" within the list of settings sections will take you to the user
- management screen. Here you can add new users, edit the properties and privileges of
- existing users, and view the times that each user last logged in. If you have a large
- number of users, you can also enter search terms within the "Filter" field to filter the
- list of users by username.</para>
- <para>To add a new user, click the "New User" button. This will take you to a screen where
- you will be allowed to enter the details of the new user, such as the password and
- username. Note that, unless you specify otherwise, the new user will have no access to
- any existing connections, nor any administrative privileges, and you will need to
- manually set the user's password before they will be able to log in.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/manage-users.png" format="PNG" contentwidth="5in"
- />
- </imageobject>
- <caption>
- <para>User management interface</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <para>To edit a user, just click on the user you wish to edit. You will be taken to a screen
- which allows you to change the user's password, expire their password (such that it must
- be changed at next login), add or remove administrative permissions, and add or remove
- read access to specific connections, sharing profiles, or groups. If you are managing a
- large number of connections or groups and wish to reduce the size of the list displayed,
- you can do so by specifying search terms within the "Filter" field. Groups will be
- filtered by name and connections will be filtered by name or protocol.</para>
- <para>If you have delete permission on the user, you will also see a "Delete" button.
- Clicking this button will permanently delete the user. Alternatively, if you only wish
- to temporarily disable the account, checking "Login disabled" will achieve the same
- effect while not removing the user entirely. If they attempt to log in, the attempt will
- be rejected as if their account did not exist at all.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/edit-user.png" format="PNG" contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Editing a user</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <section xml:id="user-group-membership">
- <title>Editing group membership</title>
- <para>When editing a user, the groups that user is a member of may be modified within
- the "Groups" section. By default, only groups that the user is already a member of
- will be displayed. If you have permission to modify the user's membership within a
- group, an "X" icon will be available next to that group's name. Clicking the "X"
- will remove the user from that group, taking effect after the user is saved.</para>
- <para>To add users to a group, the arrow next to the list of groups must be clicked to
- expand the section and reveal all available groups. Available groups may then be
- checked/unchecked to modify the user's membership within those groups:</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/edit-user-membership.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Editing group membership of a user</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <para>If you have a large number of available groups, you can also enter search terms
- within the "Filter" field to filter the list of groups by name.</para>
- </section>
- </section>
- <section xml:id="user-group-management">
- <title>User group management</title>
- <indexterm>
- <primary>user group management</primary>
- </indexterm>
- <indexterm>
- <primary>user groups</primary>
- </indexterm>
- <indexterm>
- <primary>groups</primary>
- </indexterm>
- <para>Clicking "Groups" within the list of settings sections will take you to the user group
- management screen. Here you can add new groups and edit the properties and privileges of
- existing groups. If you have a large number of user groups, you can also enter search
- terms within the "Filter" field to filter the list of groups by name:</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/manage-groups.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>User group management interface</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <para>To add a new group, click the "New Group" button. This will take you to a screen where
- you will be allowed to enter the details of the new group, including membership and any
- permissions that members of the group should have.</para>
- <para>To edit a group, just click on the group you wish to edit. You will be taken to a
- screen which allows you to modify membership, add or remove administrative permissions,
- and add or remove read access to specific connections, sharing profiles, or connection
- groups. If you are managing a large number of connections or groups and wish to reduce
- the size of the list displayed, you can do so by specifying search terms within the
- "Filter" field. Connection groups will be filtered by name and connections will be
- filtered by name or protocol.</para>
- <para>If you have delete permission on the group, you will also see a "Delete" button.
- Clicking this button will permanently delete the group. Alternatively, if you only wish
- to temporarily disable the effects of membership in the group, checking "Disabled" will
- achieve the same effect while not removing the group entirely.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/edit-user-group.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Editing a user group</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <section>
- <title>Group membership of groups</title>
- <para>Managing the group membership of groups is more complex than that of users, as
- groups may contain both users and groups, with permissions from parent groups
- possibly being inherited. Parent groups, member groups, and member users, can all be
- managed identically to the <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="user-group-membership">group memberships of users</link>, with a
- corresponding section dedicated to each within the user group editor:</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/edit-group-memberships.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Editing the various membership relations of a user group</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <para>Note that it is ultimately up to the extension providing the group to determine
- how permissions granted to that group are inherited, if at all. The <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="jdbc-auth">database
- authentication extension</link> implements full recursive inheritance of group
- permissions, with permissions granted to a group being granted to all
- members/descendants of that group, regardless of how deeply those members are
- nested.</para>
- </section>
- </section>
- <section xml:id="connection-management">
- <title>Connections and connection groups</title>
- <indexterm>
- <primary>connection management</primary>
- </indexterm>
- <indexterm>
- <primary>connection groups</primary>
- </indexterm>
- <indexterm>
- <primary>groups</primary>
- </indexterm>
- <para>Clicking "Connections" within the list of settings sections will take you to the
- connection management screen. The connection management screen allows administrators to
- create and edit connections, sharing profiles, and connection groups. If you have a
- large number of connections, you can also enter search terms within the "Filter" field
- to filter the list of connections by name or protocol.</para>
- <para>To add a new connection or connection group, click the "New Connection" or "New Group"
- button, or the "New Connection" or "New Group" placeholders which appear when you expand
- an existing connection group. These options will take you to a screen where you will be
- allowed to enter the details of the new object, such as its location, parameters, and
- name. This name should be descriptive, but must also be unique with respect to other
- objects in the same location.</para>
- <para>Once you click "Save", the new object will be added, but will initially only be usable
- by administrators and your current user. To grant another user access to the new
- connection or connection group, you must <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="user-management">edit that
- user</link> or <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="user-group-management">a user group that the user is a member of</link>,
- checking the box corresponding to the connection or connection group you created.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/manage-connections.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Connection management interface</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <para>Editing connections, sharing profiles, and connection groups works identically to
- editing a user. Click on the object you wish to edit, and you will be taken to screen
- which allows you to edit it. The screen will display all properties of the object,
- including its usage history, if applicable.</para>
- <para>If you have delete permission on the object, you will also see a "Delete" button.
- Clicking this button will permanently delete the object being edited.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/edit-connection.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Editing a connection</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <section xml:id="connection-group-management">
- <title>Connection organization and balancing</title>
- <para>Connection groups can be either "organizational" or "balancing". Each group can
- contain any number of other connections or groups, but the semantics of the group
- change depending on the type.</para>
- <para>An organizational group behaves exactly as a folder or directory in a file system.
- It simply contains connections and other groups, but provides no other behavior.
- Clicking on an organizational group within a connection list will expand the group,
- revealing its contents.</para>
- <para>A balancing group behaves as a connection. It dynamically balances load across the
- connections it contains, choosing the connection with the fewest number of active
- users. Unlike organizational groups, clicking on a balancing group causes a new
- connection to be opened. The actual underlying connection used depends on which
- connection has the least load at the time the group was clicked, and whether session
- affinity is enabled on that group.</para>
- <para><indexterm>
- <primary>session affinity</primary>
- </indexterm>Enabling session affinity for a balancing group ensures that users are
- consistently routed to the same underlying connections until they log out of
- Guacamole. The load balancing behavior of the balancing group will apply only for
- the first time a particular user connects to the group. If your users may lose their
- desktop state if they are routed to a different underlying connection, this option
- should be enabled.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/edit-group.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Editing a connection group</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- </section>
- <section>
- <title>Connection sharing</title>
- <para>The ability to share a connection is governed through the use of "sharing
- profiles". If a sharing profile is created for a connection, users with access to
- both that connection and that sharing profile will be able to share the connection
- with other users by <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="client-share-menu">generating connection sharing links</link>, even if
- those users do not otherwise have user accounts within Guacamole.</para>
- <para>The name of the sharing profile will be presented an option within the <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="client-share-menu">share
- menu</link> for any users with access, while the level of access granted to
- users of generated share links will be dictated by the parameters specified for the
- sharing profile.</para>
- <important>
- <para><emphasis>The only extension which ships with Guacamole and implements enough
- of the <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-ext">Guacamole extension API</link> to share its
- connections is the <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="jdbc-auth">database authentication extension</link></emphasis>.
- If you wish to share connections (or allow your users to share connections), you
- will need to use the database authentication extension to store those
- connections.</para>
- <para>If you need to use other authentication schemes, keep in mind that the
- database authentication extension can be used <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="ldap-and-database"
- >alongside other extensions</link>, with the database handling connection
- storage and permissions only. Writing your own extension which supports sharing
- is another alternative, though that may be overly complicated if everything you
- need is already provided.</para>
- </important>
- <para>Unlike connections and groups, there is no "New Sharing Profile" button. Sharing
- profiles are created through clicking the "New Sharing Profile" placeholders which
- appear when connections are expanded. Just as expanding a connection group reveals
- the connections or groups therein, expanding a connection reveals the sharing
- profiles associated with that connection. This holds true with both <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="connection-management">the
- list of connections in the connection management screen</link> and <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="user-management">the list of
- connections in the user editor</link>.</para>
- <para>Creating or editing a sharing profile is virtually identical to creating or
- editing a connection, with the exception that not all connection parameters are
- available:</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/edit-sharing-profile.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>Editing a sharing profile</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/architecture.xml b/src/chapters/architecture.xml
deleted file mode 100644
index be9c596..0000000
--- a/src/chapters/architecture.xml
+++ /dev/null
@@ -1,145 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="guacamole-architecture" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Implementation and architecture</title>
- <indexterm>
- <primary>history</primary>
- </indexterm>
- <indexterm>
- <primary>architecture</primary>
- </indexterm>
- <indexterm>
- <primary>implementation</primary>
- </indexterm>
- <para>Guacamole is not a self-contained web application and is made up of many parts. The web
- application is actually intended to be simple and minimal, with the majority of the
- gruntwork performed by lower-level components.<informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guac-arch.png" width="2.5in"/>
- </imageobject>
- </mediaobject>
- </informalfigure></para>
- <para>Users connect to a Guacamole server with their web browser. The Guacamole client, written
- in JavaScript, is served to users by a webserver within the Guacamole server. Once loaded,
- this client connects back to the server over HTTP using the Guacamole protocol.</para>
- <para>The web application deployed to the Guacamole server reads the Guacamole protocol and
- forwards it to guacd, the native Guacamole proxy. This proxy actually interprets the
- contents of the Guacamole protocol, connecting to any number of remote desktop servers on
- behalf of the user.</para>
- <para>The Guacamole protocol combined with guacd provide protocol agnosticism: neither the
- Guacamole client nor the web application need to be aware of what remote desktop protocol is
- actually being used.</para>
- <section xml:id="guacamole-protocol-architecture">
- <title>The Guacamole protocol </title>
- <indexterm>
- <primary>Guacamole protocol</primary>
- </indexterm>
- <indexterm>
- <primary>protocol</primary>
- </indexterm>
- <para>The web application does not understand any remote desktop protocol at all. It does
- not contain support for VNC or RDP or any other protocol supported by the Guacamole
- stack. It actually only understands the Guacamole protocol, which is a protocol for
- remote display rendering and event transport. While a protocol with those properties
- would naturally have the same abilities as a remote desktop protocol, the design
- principles behind a remote desktop protocol and the Guacamole protocol are different:
- the Guacamole protocol is not intended to implement the features of a specific desktop
- environment.</para>
- <para>As a remote display and interaction protocol, Guacamole implements a superset of
- existing remote desktop protocols. Adding support for a particular remote desktop
- protocol (like RDP) to Guacamole thus involves writing a middle layer which "translates"
- between the remote desktop protocol and the Guacamole protocol. Implementing such a
- translation is no different than implementing any native client, except that this
- particular implementation renders to a remote display rather than a local one.</para>
- <para>The middle layer that handles this translation is guacd.</para>
- </section>
- <section xml:id="guacd">
- <title>guacd</title>
- <indexterm>
- <primary>guacd</primary>
- </indexterm>
- <indexterm>
- <primary>client plugin</primary>
- </indexterm>
- <para>guacd is the heart of Guacamole which dynamically loads support for remote desktop
- protocols (called "client plugins") and connects them to remote desktops based on
- instructions received from the web application.</para>
- <para>guacd is a daemon process which is installed along with Guacamole and runs in the
- background, listening for TCP connections from the web application. guacd also does not
- understand any specific remote desktop protocol, but rather implements just enough of
- the Guacamole protocol to determine which protocol support needs to be loaded and what
- arguments must be passed to it. Once a client plugin is loaded, it runs independently of
- guacd and has full control of the communication between itself and the web application
- until the client plugin terminates.</para>
- <indexterm>
- <primary><package>libguac</package></primary>
- <secondary>relationship with <package>guacd</package></secondary>
- </indexterm>
- <para>guacd and all client plugins depend on a common library, libguac, which makes
- communication via the Guacamole protocol easier and a bit more abstract.</para>
- </section>
- <section xml:id="web-application">
- <title>The web application</title>
- <indexterm>
- <primary>web application</primary>
- </indexterm>
- <para>The part of Guacamole that a user actually interacts with is the web
- application.</para>
- <para>The web application, as mentioned before, does not implement any remote desktop
- protocol. It relies on guacd, and implements nothing more than a spiffy web interface
- and authentication layer.</para>
- <para>We chose to implement the server side of the web application in Java, but there's no
- reason that it can't be written in a different language. In fact, because Guacamole is
- intended be an API, we encourage this.</para>
- </section>
- <section xml:id="realmint">
- <title>RealMint</title>
- <indexterm>
- <primary>history</primary>
- </indexterm>
- <para>Guacamole is now a generalized remote desktop gateway, but this was not always the
- case. Guacamole began as a purely text-based Telnet client written in JavaScript called
- <application xl:href="http://sourceforge.net/projects/realmint"
- >RealMint</application> ("RealMint" is an anagram for "terminal"). It was written
- mainly as a demonstration and, while intended to be useful, its main claim to fame was
- only that it was pure JavaScript.</para>
- <para>The tunnel used by RealMint was written in PHP. In contrast to Guacamole's HTTP
- tunnel, RealMint's tunnel used only simple long-polling and was inefficient. RealMint
- had a decent keyboard implementation which lives on now in parts of Guacamole's keyboard
- code, but this was really the extent of RealMint's features and usability.</para>
- <para>Given that it was just an implementation of a legacy protocol, and that several other
- JavaScript terminal emulators exist, most of which well-established and stable, the
- project was dropped.</para>
- </section>
- <section xml:id="vnc-client">
- <title>VNC Client</title>
- <para>Once the developers learned of the HTML5 canvas tag, and saw that it was already
- implemented in Firefox and Chrome, work started instead on a proof-of-concept JavaScript
- VNC client.</para>
- <para>This client was purely JavaScript with a Java server component, and worked by
- translating VNC into an XML-based version of the same. Its development was naturally
- driven by VNC's features, and its scope was limited to forwarding a single connection to
- a set of users. Although relatively slow, the proof-of-concept worked well enough that
- the project needed an online place to live, and was registered with SourceForge as
- "Guacamole" - an HTML5 VNC client.</para>
- <para>As Guacamole grew and became more than a proof-of-concept, the need for speed
- increased, and the old RealMint-style long polling was dropped, as was the use of
- XML.</para>
- <para>As WebSocket could not be trusted to be supported at the time, and Java had no
- WebSocket standard for servlets, an equivalent HTTP-based tunnel was developed. This
- tunnel is still used today if WebSocket cannot be used for any reason.</para>
- </section>
- <section xml:id="gateway">
- <title>Remote Desktop Gateway</title>
- <para>A faster text-based protocol was developed which could present the features of
- multiple remote desktop protocols, not just VNC. The entire system was rearchitected
- into a standard daemon, guacd, and a common library, libguac, which drove both the
- daemon and protocol support, which became extendable.</para>
- <para>The scope of the project expanded from an adequate VNC client to a performant HTML5
- remote desktop gateway and general API. In its current state, Guacamole can be used as a
- central gateway to access any number of machines running different remote desktop
- servers. It provides extendable authentication, and in the case you need something more
- specialized, a general API for HTML5-based remote access.</para>
- </section>
-</chapter>
diff --git a/src/chapters/cas-auth.xml b/src/chapters/cas-auth.xml
deleted file mode 100644
index fed8cdc..0000000
--- a/src/chapters/cas-auth.xml
+++ /dev/null
@@ -1,167 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="cas-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>CAS Authentication</title>
- <indexterm>
- <primary>CAS Authentication</primary>
- </indexterm>
- <para>CAS is an open-source Single Sign On (SSO) provider that allows multiple applications
- and services to authenticate against it and brokers those authentication requests to a
- back-end authentication provider. This module allows Guacamole to redirect to CAS for
- authentication and user services. This module must be layered on top of other authentication
- extensions that provide connection information, as it only provides user authentication.
- </para>
- <section xml:id="cas-downloading">
- <title>Downloading the CAS authentication extension</title>
- <para>The CAS authentication extension is available separately from the main
- <filename>guacamole.war</filename>. The link for this and all other
- officially-supported and compatible extensions for a particular version of Guacamole are
- provided on the release notes for that version. You can find the release notes for
- current versions of Guacamole here: <link
- xlink:href="http://guacamole.apache.org/releases/"
- >http://guacamole.apache.org/releases/</link>.</para>
- <para>The CAS authentication extension is packaged as a <filename>.tar.gz</filename>
- file containing only the extension itself,
- <filename>guacamole-auth-cas-1.3.0.jar</filename>, which must
- ultimately be placed in <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </section>
- <section xml:id="installing-cas-auth">
- <title>Installing CAS authentication</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- located within the <filename>GUACAMOLE_HOME/extensions</filename> directory.
- <emphasis>If you are unsure where <varname>GUACAMOLE_HOME</varname> is located on
- your system, please consult <xref linkend="configuring-guacamole"/> before
- proceeding.</emphasis></para>
- <para>To install the CAS authentication extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Copy <filename>guacamole-auth-cas-1.3.0.jar</filename> within
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </step>
- <step>
- <para>Configure Guacamole to use CAS authentication, as described
- below.</para>
- </step>
- </procedure>
- <section xml:id="guac-cas-config">
- <title>Configuring Guacamole for CAS Authentication</title>
- <indexterm>
- <primary>configuring CAS authentication</primary>
- </indexterm>
- <indexterm>
- <primary>CAS authentication</primary>
- <secondary>configuration</secondary>
- </indexterm>
- <para>Guacamole's CAS support requires specifying two properties that describe the CAS
- authentication server and the Guacamole deployment. These properties are
- <emphasis>absolutely required in all cases</emphasis>, as they dictate how
- Guacamole should connect to the CAS and how CAS should redirect users back to
- Guacamole once their identity has been confirmed:</para>
- <variablelist>
- <varlistentry>
- <term><property>cas-authorization-endpoint</property></term>
- <listitem>
- <para>The URL of the CAS authentication server. This should be the full
- path to the base of the CAS installation.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>cas-redirect-uri</property></term>
- <listitem>
- <para>The URI to redirect back to upon successful authentication. Normally
- this will be the full URL of your Guacamole installation.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Additional optional properties are available to control how CAS tokens are
- processed, including whether <link linkend="cas-clearpass">CAS ClearPass</link>
- should be used and how user group memberships should be derived:</para>
- <variablelist>
- <varlistentry>
- <term><property>cas-clearpass-key</property></term>
- <listitem>
- <para>If using CAS ClearPass to pass the SSO password to Guacamole, this
- parameter specifies the private key file to use to decrypt the password.
- See <link linkend="cas-clearpass">the section on ClearPass</link>
- below.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>cas-group-attribute</property></term>
- <listitem>
- <para>The CAS attribute that determines group membership, typically
- "<property>memberOf</property>". This parameter is only required if
- using CAS to define user group memberships. If omitted, groups aren't
- retrieved from CAS, and all other group-related properties for CAS are
- ignored.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>cas-group-format</property></term>
- <listitem>
- <para>The format that CAS will use for its group names. Possible values are
- <constant>plain</constant>, for groups that are simple text names,
- or <constant>ldap</constant>, for groups that are represented as LDAP
- DNs. If set to <constant>ldap</constant>, group names are always
- determined from the last (leftmost) attribute of the DN. If omitted,
- <constant>plain</constant> is used by default.</para>
- <para>This property has no effect if
- <property>cas-group-attribute</property> is not set.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>cas-group-ldap-base-dn</property></term>
- <listitem>
- <para>The base DN to require for LDAP-formatted CAS groups. If specified,
- only CAS groups beneath this DN will be included, and all other CAS
- groups will be ignored.</para>
- <para>This property has no effect if <property>cas-group-format</property>
- is not <constant>ldap</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>cas-group-ldap-attribute</property></term>
- <listitem>
- <para>The LDAP attribute to require for LDAP-formatted CAS groups. If
- specified, only CAS groups that use this attribute for the name of the
- group will be included. Note that LDAP group names are <emphasis>always
- determined from the last (leftmost) attribute of the DN</emphasis>.
- Specifying this property will only have the effect of ignoring any
- groups that do not use the specified attribute to represent the group
- name.</para>
- <para>This property has no effect if <property>cas-group-format</property>
- is not <constant>ldap</constant>.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="completing-cas-install">
- <title>Completing the installation</title>
- <para>Guacamole will only reread <filename>guacamole.properties</filename> and load
- newly-installed extensions during startup, so your servlet container will need to be
- restarted before CAS authentication can be used. <emphasis>Doing this will
- disconnect all active users, so be sure that it is safe to do so prior to
- attempting installation.</emphasis> When ready, restart your servlet container
- and give the new authentication a try.</para>
- </section>
- <section xml:id="cas-clearpass">
- <title>Using CAS ClearPass</title>
- <para>CAS has a function called ClearPass that can be used to cache the password
- used for SSO authentication and make that available to services at a later
- time. Configuring the CAS server for ClearPass is beyond the scope of this
- article - more information can be found on the Apereo CAS wiki at the
- following URL: <link xlink:href="https://apereo.github.io/cas">
- https://apereo.github.io/cas</link>.</para>
- <para>Once you have CAS configured for credential caching, you need to configure
- the service with a keypair for passing the credential securely. The public
- key gets installed on the CAS server, while the private key gets configured
- with the <property>cas-clearpass-key</property> property. The private key
- file needs to be in RSA PKCS8 format.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/configuring.xml b/src/chapters/configuring.xml
deleted file mode 100644
index efdf47b..0000000
--- a/src/chapters/configuring.xml
+++ /dev/null
@@ -1,6670 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="configuring-guacamole"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
-
- <title>Configuring Guacamole</title>
- <para>After installing Guacamole, you need to configure users and connections before Guacamole
- will work. This chapter covers general configuration of Guacamole and the use of its default
- authentication method.</para>
- <para>Guacamole's default authentication method reads all users and connections from a single
- file called <filename>user-mapping.xml</filename>. This authentication method is intended to
- be:</para>
- <orderedlist>
- <listitem>
- <para>Sufficient for small deployments of Guacamole.</para>
- </listitem>
- <listitem>
- <para>A relatively-easy means of verifying that Guacamole has been properly set
- up.</para>
- </listitem>
- </orderedlist>
- <para>Other, more complex authentication methods which use backend databases, LDAP, etc. are
- discussed in a separate, dedicated chapters.</para>
- <para>Regardless of the authentication method you use, Guacamole's configuration always consists
- of two main pieces: a directory referred to as <varname>GUACAMOLE_HOME</varname>, which is
- the primary search location for configuration files, and
- <filename>guacamole.properties</filename>, the main configuration file used by Guacamole
- and its extensions.</para>
- <section xml:id="guacamole-home">
- <title><varname>GUACAMOLE_HOME</varname> (<filename>/etc/guacamole</filename>)</title>
- <indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary><varname>GUACAMOLE_HOME</varname></primary>
- </indexterm>
- <para><varname>GUACAMOLE_HOME</varname> is the name given to Guacamole's configuration
- directory, which is located at <filename>/etc/guacamole</filename> by default. All
- configuration files, extensions, etc. reside within this directory. The structure of
- <varname>GUACAMOLE_HOME</varname> is rigorously defined, and consists of the
- following optional files:</para>
- <variablelist>
- <varlistentry>
- <term><filename>guacamole.properties</filename></term>
- <listitem>
- <para>The main Guacamole configuration file. Properties within this file dictate
- how Guacamole will connect to <package>guacd</package>, and may configure
- the behavior of installed authentication extensions.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>logback.xml</filename></term>
- <listitem>
- <para>Guacamole uses a logging system called Logback for all messages. By
- default, Guacamole will log to the console only, but you can change this by
- providing your own Logback configuration file.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>extensions/</filename></term>
- <listitem>
- <para>The install location for all Guacamole extensions. Guacamole will
- automatically load all <filename>.jar</filename> files within this directory
- on startup.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>lib/</filename></term>
- <listitem>
- <para>The search directory for libraries required by any Guacamole extensions.
- Guacamole will make the <filename>.jar</filename> files within this
- directory available to all extensions. If your extensions require additional
- libraries, such as database drivers, this is the proper place to put
- them.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <section xml:id="overriding-guacamole-home">
- <title>Overriding <varname>GUACAMOLE_HOME</varname></title>
- <para>If you cannot or do not wish to use <filename>/etc/guacamole</filename> for
- <varname>GUACAMOLE_HOME</varname>, the location can be overridden through any of
- the following methods:</para>
- <orderedlist>
- <listitem>
- <para>Creating a directory named <filename>.guacamole</filename>, within the
- home directory of <emphasis>the user running the servlet
- container</emphasis>. This directory will automatically be used for
- <varname>GUACAMOLE_HOME</varname> if it exists.</para>
- </listitem>
- <listitem>
- <para>Specifying the full path to an alternative directory with the environment
- variable <varname>GUACAMOLE_HOME</varname>. <emphasis>Be sure to consult the
- documentation for your servlet container to determine how to properly
- set environment variables.</emphasis></para>
- </listitem>
- <listitem>
- <para>Specifying the full path to an alternative directory with the system
- property <property>guacamole.home</property>.</para>
- </listitem>
- </orderedlist>
- </section>
- </section>
-
- <section xml:id="initial-setup">
- <title><filename>guacamole.properties</filename></title>
- <indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary><filename>guacamole.properties</filename></primary>
- </indexterm>
- <indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>configuration</primary>
- </indexterm>
- <para>The Guacamole web application uses one main configuration file called
- <filename>guacamole.properties</filename>. This file is the common location for all
- configuration properties read by Guacamole or any extension of Guacamole, including
- authentication providers.</para>
- <para>In previous releases, this file had to be in the classpath of your servlet container.
- Now, the location of <filename>guacamole.properties</filename> can be explicitly defined
- with environment variables or system properties, and the classpath is only used as a
- last resort. When searching for <filename>guacamole.properties</filename>, Guacamole
- will check, in order:</para>
- <orderedlist>
- <listitem>
- <para>Within <varname>GUACAMOLE_HOME</varname>, as defined above.</para>
- </listitem>
- <listitem>
- <para>The classpath of the servlet container.</para>
- </listitem>
- </orderedlist>
- <para>The <filename>guacamole.properties</filename> file is optional and is used to
- configure Guacamole in situations where the defaults are insufficient, or to provide
- additional configuration information for extensions. There are several standard
- properties that are always available for use:</para>
- <variablelist>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>api-session-timeout</primary>
- </indexterm><parameter>api-session-timeout</parameter></term>
- <listitem>
- <para>The amount of time, in minutes, to allow Guacamole sessions
- (authentication tokens) to remain valid despite inactivity. If omitted,
- Guacamole sessions will expire after 60 minutes of inactivity.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>api-max-request-size</primary>
- </indexterm><parameter>api-max-request-size</parameter></term>
- <listitem>
- <para>The maximum number of bytes to accept within the entity body of any
- particular HTTP request, where 0 indicates that no limit should be applied.
- If omitted, requests will be limited to 2097152 bytes (2 MB) by default.
- This limit does not apply to file uploads.</para>
- <para>If using a reverse proxy for SSL termination, <emphasis>keep in mind that
- reverse proxies may enforce their own limits independently of
- this</emphasis>. For example, <link
- xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="nginx-file-upload-size">Nginx will enforce a 1 MB request size
- limit by default</link>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>allowed-languages</primary>
- </indexterm><parameter>allowed-languages</parameter></term>
- <listitem>
- <para>A comma-separated whitelist of language keys to allow as display language
- choices within the Guacamole interface. For example, to restrict Guacamole
- to only English and German, you would specify:</para>
- <informalexample>
- <programlisting>allowed-languages: en, de</programlisting>
- </informalexample>
- <para>As English is the fallback language, used whenever a translation key is
- missing from the chosen language, English should only be omitted from this
- list if you are absolutely positive that no strings are missing.</para>
- <para>The corresponding JSON of any built-in languages not listed here will
- still be available over HTTP, but the Guacamole interface will not use them,
- nor will they be used automatically based on local browser language. If
- omitted, all defined languages will be available.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>enable-environment-properties</primary>
- </indexterm><parameter>enable-environment-properties</parameter></term>
- <listitem>
- <para>If set to "true", Guacamole will first evaluate its environment to obtain
- the value for any given configuration property, before using a value specified
- in <filename>guacamole.properties</filename> or falling back to a default
- value. By enabling this option, you can easily override any other configuration
- property using an environment variable.</para>
- <informalexample>
- <programlisting>enable-environment-properties: true</programlisting>
- </informalexample>
- <para>When searching for a configuration property in the environment, the name of
- the property is first transformed by converting all lower case characters to
- their upper case equivalents, and by replacing all hyphen characters (<code>-</code>) with
- underscore characters (<code>_</code>). For example, the
- <parameter>guacd-hostname</parameter> property would be transformed to
- <parameter>GUACD_HOSTNAME</parameter> when searching the environment.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>guacd-hostname</primary>
- </indexterm><parameter>guacd-hostname</parameter></term>
- <listitem>
- <para>The host the Guacamole proxy daemon (<package>guacd</package>) is
- listening on. If omitted, Guacamole will assume <package>guacd</package> is
- listening on localhost.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>guacd-port</primary>
- </indexterm><parameter>guacd-port</parameter></term>
- <listitem>
- <para>The port the Guacamole proxy daemon (<package>guacd</package>) is
- listening on. If omitted, Guacamole will assume <package>guacd</package> is
- listening on port 4822.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>guacd-ssl</primary>
- </indexterm><parameter>guacd-ssl</parameter></term>
- <listitem>
- <para>If set to "true", Guacamole will require SSL/TLS encryption between the
- web application and <package>guacd</package>. By default, communication
- between the web application and <package>guacd</package> will be
- unencrypted.</para>
- <para>Note that if you enable this option, you must also configure
- <package>guacd</package> to use SSL via command line options. These
- options are documented in the manpage of <package>guacd</package>. You will
- need an SSL certificate and private key.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>skip-if-unavailable</primary>
- </indexterm><parameter>skip-if-unavailable</parameter></term>
- <listitem>
- <para>A comma-separated list of the identifiers of authentication providers that
- should be allowed to fail internally without aborting the authentication
- process. For example, to request that Guacamole ignore failures due to the
- LDAP directory or MySQL server being unexpectedly down, allowing other
- authentication providers to continue functioning:</para>
- <informalexample>
- <programlisting>skip-if-unavailable: mysql, ldap</programlisting>
- </informalexample>
- <para>By default, Guacamole takes a conservative approach to internal failures,
- aborting the authentication process if an internal error occurs within any
- authentication provider. Depending on the nature of the error, this may mean
- that no users can log in until the cause of the failure is dealt with. The
- <parameter>skip-if-unavailable</parameter> property may be used to
- explicitly inform Guacamole that one or more underlying systems are expected
- to occasionally experience failures, and that other functioning systems
- should be relied upon if they do fail.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <example>
- <title>Example <filename>guacamole.properties</filename></title>
- <programlisting xml:id="guacamole.properties" version="5.0" xml:lang="en"># Hostname and port of guacamole proxy
-guacd-hostname: localhost
-guacd-port: 4822</programlisting>
- </example>
- </section>
- <section xml:id="webapp-logging">
- <title>Logging within the web application</title>
- <indexterm>
- <primary>logging</primary>
- </indexterm>
- <para>By default, Guacamole logs all messages to the console. Servlet containers like Tomcat
- will automatically redirect these messages to a log file,
- <filename>catalina.out</filename> in the case of Tomcat, which you can read through
- while Guacamole runs. Messages are logged at four different log levels, depending on
- message importance and severity:</para>
- <variablelist>
- <varlistentry>
- <term><indexterm>
- <primary>logging</primary>
- <secondary>errors</secondary>
- </indexterm><constant>error</constant></term>
- <listitem>
- <para>Errors are fatal conditions. An operation, described in the log message,
- was attempted but could not proceed, and the failure of this operation is a
- serious problem that needs to be addressed.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm>
- <primary>logging</primary>
- <secondary>warnings</secondary>
- </indexterm><constant>warn</constant></term>
- <listitem>
- <para>Warnings are generally non-fatal conditions. The operation continued, but
- encountered noteworthy problems.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm>
- <primary>logging</primary>
- <secondary>info</secondary>
- </indexterm><constant>info</constant></term>
- <listitem>
- <para>"Info" messages are purely informational. They may be useful or
- interesting to administrators, but are not generally critical to proper
- operation of a Guacamole server.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm>
- <primary>logging</primary>
- <secondary>debug</secondary>
- </indexterm><constant>debug</constant></term>
- <listitem>
- <para>Debug messages are highly detailed and oriented toward development. Most
- debug messages will contain stack traces and internal information that is
- useful when investigating problems within code. It is expected that debug
- messages, though verbose, will not affect performance.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><indexterm>
- <primary>logging</primary>
- <secondary>trace</secondary>
- </indexterm><constant>trace</constant></term>
- <listitem>
- <para>Trace messages are similar to debug messages in intent and verbosity, but
- are so low-level that they may affect performance due to their frequency.
- Trace-level logging is rarely necessary, and is mainly useful in providing
- highly detailed context around issues being investigated.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Guacamole logs messages using a logging framework called <link
- xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://logback.qos.ch/"
- >Logback</link> and, by default, will only log messages at the
- "<constant>info</constant>" level or higher. If you wish to change the log level, or
- configure how or where Guacamole logs messages, you can do so by providing your own
- <filename>logback.xml</filename> file within <varname>GUACAMOLE_HOME</varname>. For
- example, to log all messages to the console, even "<constant>debug</constant>" messages,
- you might use the following <filename>logback.xml</filename>:</para>
- <informalexample>
- <programlisting><configuration>
-
- <!-- Appender for debugging -->
- <appender name="GUAC-DEBUG" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
- </encoder>
- </appender>
-
- <!-- Log at DEBUG level -->
- <root level="debug">
- <appender-ref ref="GUAC-DEBUG"/>
- </root>
-
-</configuration></programlisting>
- </informalexample>
- <para>Guacamole and the above example configure only one appender which logs to the console,
- but Logback is extremely flexible and allows any number of appenders which can each log
- to separate files, the console, etc. based on a number of criteria, including the log
- level and the source of the message.</para>
- <para>More thorough <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="http://logback.qos.ch/manual/configuration.html">documentation on
- configuring Logback</link> is provided on the Logback project's web site.</para>
- </section>
- <section xml:id="basic-auth">
- <title>Using the default authentication</title>
- <indexterm>
- <primary>authentication</primary>
- </indexterm>
- <para>Guacamole's default authentication module is simple and consists of a mapping of
- usernames to configurations. This authentication module comes with Guacamole and simply
- reads usernames and passwords from an XML file. It is always enabled, but will only read
- from the XML file if it exists, and is always last in priority relative to any other
- authentication extensions.</para>
- <para>There are other authentication modules available. The Guacamole project provides
- database-backed authentication modules with the ability to manage connections and users
- from the web interface, and other authentication modules can be created using the
- extension API provided along with the Guacamole web application,
- <package>guacamole-ext</package>.</para>
- <section xml:id="user-mapping">
- <title><filename>user-mapping.xml</filename></title>
- <indexterm>
- <primary>user-mapping.xml</primary>
- </indexterm>
- <para>The default authentication provider used by Guacamole reads all username,
- password, and configuration information from a file called the "user mapping"
- located at <filename>GUACAMOLE_HOME/user-mapping.xml</filename>. An example of a
- user mapping file is included with Guacamole, and looks something like this:</para>
- <programlisting><user-mapping>
-
- <!-- Per-user authentication and config information -->
- <authorize username="USERNAME" password="PASSWORD">
- <protocol>vnc</protocol>
- <param name="hostname">localhost</param>
- <param name="port">5900</param>
- <param name="password">VNCPASS</param>
- </authorize>
-
- <!-- Another user, but using md5 to hash the password
- (example below uses the md5 hash of "PASSWORD") -->
- <authorize
- username="USERNAME2"
- password="319f4d26e3c536b5dd871bb2c52e3178"
- encoding="md5">
-
- <!-- First authorized connection -->
- <connection name="localhost">
- <protocol>vnc</protocol>
- <param name="hostname">localhost</param>
- <param name="port">5901</param>
- <param name="password">VNCPASS</param>
- </connection>
-
- <!-- Second authorized connection -->
- <connection name="otherhost">
- <protocol>vnc</protocol>
- <param name="hostname">otherhost</param>
- <param name="port">5900</param>
- <param name="password">VNCPASS</param>
- </connection>
-
- </authorize>
-
-</user-mapping></programlisting>
- <para>Each user is specified with a corresponding
- <code><authorize></code> tag. This tag contains all
- authorized connections for that user, each denoted with a
- <code><connection></code> tag. Each
- <code><connection></code> tag contains a corresponding
- protocol and set of protocol-specific parameters, specified with
- the <code><protocol></code> and <code><param></code> tags
- respectively.</para>
- <section xml:id="user-setup">
- <title>Adding users</title>
- <indexterm>
- <primary>users</primary>
- <secondary>adding</secondary>
- </indexterm>
- <para>When using
- <classname>BasicFileAuthenticationProvider</classname>,
- username/password pairs are specified with
- <code><authorize></code> tags, which each have a
- <code>username</code> and <code>password</code>
- attribute. Each <code><authorize></code> tag authorizes a
- specific username/password pair to access all connections
- within the tag:</para>
- <programlisting><authorize username="<replaceable>USER</replaceable>" password="<replaceable>PASS</replaceable>">
- ...
-</authorize></programlisting>
- <para>In the example above, the password would be listed in
- plaintext. If you don't want to do this, you can also
- specify your password hashed with MD5:</para>
- <programlisting><authorize username="<replaceable>USER</replaceable>"
- password="<replaceable>319f4d26e3c536b5dd871bb2c52e3178</replaceable>"
- encoding="md5">
- ...
-</authorize></programlisting>
- <para>After modifying user-mapping.xml, the file will be
- automatically reread by Guacamole, and your changes will
- take effect immediately. The newly-added user will be able
- to log in - no restart of the servlet container is
- needed.</para>
- </section>
- <section xml:id="connection-setup">
- <title>Adding connections to a user</title>
- <indexterm>
- <primary>connections</primary>
- <secondary>adding</secondary>
- </indexterm>
- <para>To specify a connection within an
- <code><authorize></code> tag, you can either list a
- single protocol and set of parameters (specified with a
- <code><protocol></code> tag and any number of
- <code><param></code> tags), in which case that user
- will have access to only one connection named "DEFAULT", or
- you can specify one or more connections with one or more
- <code><connection></code> tags, each of which can be
- named and contains a <code><protocol></code> tag and any
- number of <code><param></code> tags.</para>
- </section>
- </section>
- </section>
- <section xml:id="connection-configuration">
- <title xml:id="configuring-connections">Configuring connections</title>
- <para>Each protocol supported by Guacamole has its own set of configuration parameters.
- These parameters typically describe the hostname and port of the remote desktop server,
- the credentials to use when connecting, if any, and the size and color depth of the
- display. If the protocol supports file transfer, options for enabling that functionality
- will be provided as well.</para>
- <section xml:id="vnc">
- <title>VNC</title>
- <indexterm>
- <primary>VNC</primary>
- </indexterm>
- <para>The VNC protocol is the simplest and first protocol supported by Guacamole.
- Although generally not as fast as RDP, many VNC servers are adequate, and VNC over
- Guacamole tends to be faster than VNC by itself due to decreased bandwidth
- usage.</para>
- <para>VNC support for Guacamole is provided by the <package>libguac-client-vnc</package>
- library, which will be installed as part of guacamole-server if the required
- dependencies are present during the build.</para>
- <section xml:id="vnc-network-parameters">
- <title>Network parameters</title>
- <para>With the exception of reverse-mode VNC connections, VNC works by making
- outbound network connections to a particular host which runs one or more VNC
- servers. Each VNC server is associated with a display number, from which the
- appropriate port number is derived.</para>
- <informaltable frame="all" xml:id="vnc-parameters">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>hostname</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>hostname</secondary>
- </indexterm>The hostname or IP address of the VNC server
- Guacamole should connect to.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>port</secondary>
- </indexterm>The port the VNC server is listening on, usually
- 5900 or 5900 + <replaceable>display number</replaceable>.
- For example, if your VNC server is serving display number 1
- (sometimes written as <constant>:1</constant>), your port
- number here would be 5901.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>autoretry</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>retrying connections</secondary>
- </indexterm>The number of times to retry connecting before
- giving up and returning an error. In the case of a reverse
- connection, this is the number of times the connection
- process is allowed to time out.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-authentication">
- <title>Authentication</title>
- <para>The VNC standard defines only password based authentication. Other
- authentication mechanisms exist, but are non-standard or proprietary. Guacamole
- currently supports both standard password-only based authentication, as well
- as username and password authentication.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>username</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>username</secondary>
- </indexterm>The username to use when attempting
- authentication, if any. This parameter is optional.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>password</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>password</secondary>
- </indexterm>The password to use when attempting
- authentication, if any. This parameter is optional.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-display-settings">
- <title>Display settings</title>
- <para>VNC servers do not allow the client to request particular display sizes, so
- you are at the mercy of your VNC server with respect to display width and
- height. However, to reduce bandwidth usage, you may request that the VNC server
- reduce its color depth. Guacamole will automatically detect 256-color images,
- but this can be guaranteed for absolutely all graphics sent over the connection
- by forcing the color depth to 8-bit. Color depth is otherwise dictated by the
- VNC server.</para>
- <para>If you are noticing problems with your VNC display, such as the lack of a
- mouse cursor, the presence of multiple mouse cursors, or strange colors (such as
- blue colors appearing more like orange or red), these are typically the result
- of bugs or limitations within the VNC server, and additional parameters are
- available to work around such issues.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>color-depth</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>color depth</secondary>
- </indexterm>The color depth to request, in bits-per-pixel.
- This parameter is optional. If specified, this must be
- either 8, 16, 24, or 32. Regardless of what value is chosen
- here, if a particular update uses less than 256 colors,
- Guacamole will always send that update as a 256-color
- PNG.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>swap-red-blue</parameter></entry>
- <entry>
- <para>If the colors of your display appear wrong (blues appear
- orange or red, etc.), it may be that your VNC server is
- sending image data incorrectly, and the red and blue
- components of each color are swapped. If this is the case,
- set this parameter to "true" to work around the problem.
- This parameter is optional.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>cursor</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>mouse pointer</secondary>
- </indexterm>If set to "remote", the mouse pointer will be
- rendered remotely, and the local position of the mouse
- pointer will be indicated by a small dot. A remote mouse
- cursor will feel slower than a local cursor, but may be
- necessary if the VNC server does not support sending the
- cursor image to the client.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>encodings</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>encodings</secondary>
- </indexterm>A space-delimited list of VNC encodings to use.
- The format of this parameter is dictated by libvncclient and
- thus doesn't really follow the form of other Guacamole
- parameters. This parameter is optional, and
- <package>libguac-client-vnc</package> will use any
- supported encoding by default.</para>
- <para>Beware that this parameter is intended to be replaced with
- individual, encoding-specific parameters in a future
- release.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>read-only</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>read-only</secondary>
- </indexterm>Whether this connection should be read-only. If
- set to "true", no input will be accepted on the connection
- at all. Users will only see the desktop and whatever other
- users using that same desktop are doing. This parameter is
- optional.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>force-lossless</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>lossless compression</secondary>
- </indexterm>Whether this connection should only use lossless
- compression for graphical updates. If set to "true", lossy
- compression will not be used. This parameter is optional. By
- default, lossy compression will be used when heuristics
- determine that it would likely outperform lossless
- compression.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-recording">
- <title>Session recording</title>
- <para>VNC sessions can be recorded graphically. These recordings take the form of
- Guacamole protocol dumps and are recorded automatically to a specified
- directory. Recordings can be subsequently translated to a normal video stream
- using the <command>guacenc</command> utility provided with
- guacamole-server.</para>
- <para>For example, to produce a video called "<replaceable>NAME</replaceable>.m4v"
- from the recording "<replaceable>NAME</replaceable>", you would run:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guacenc <replaceable>/path/to/recording/NAME</replaceable></userinput></screen>
- </informalexample>
- <para>The <command>guacenc</command> utility has additional options for overriding
- default behavior, including tweaking the output format, which are documented in
- detail within the manpage:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>man guacenc</userinput></screen>
- </informalexample>
- <para>If recording of key events is explicitly enabled using the
- <parameter>recording-include-keys</parameter> parameter, recordings can also
- be translated into human-readable interpretations of the keys pressed during the
- session using the <command>guaclog</command> utility. The usage of
- <command>guaclog</command> is analogous to <command>guacenc</command>, and
- results in the creation of a new text file containing the interpreted
- events:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guaclog <replaceable>/path/to/recording/NAME</replaceable></userinput><computeroutput>
-guaclog: INFO: Guacamole input log interpreter (guaclog) version 1.3.0
-guaclog: INFO: 1 input file(s) provided.
-guaclog: INFO: Writing input events from "<replaceable>/path/to/recording/NAME</replaceable>" to "<replaceable annotations="">/path/to/recording/NAME</replaceable>.txt" ...
-guaclog: INFO: All files interpreted successfully.</computeroutput>
-<prompt>$</prompt> </screen>
- </informalexample>
- <important>
- <para>Guacamole will never overwrite an existing recording. If necessary, a
- numeric suffix like ".1", ".2", ".3", etc. will be appended to
- <replaceable>NAME</replaceable> to avoid overwriting an existing
- recording. If even appending a numeric suffix does not help, the session
- will simply not be recorded.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>recording-path</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>graphical recording</secondary>
- </indexterm>The directory in which screen recording files
- should be created. <emphasis>If a graphical recording needs
- to be created, then this parameter is
- required.</emphasis> Specifying this parameter enables
- graphical screen recording. If this parameter is omitted, no
- graphical recording will be created.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>create-recording-path</parameter></entry>
- <entry>
- <para>If set to "true", the directory specified by the
- <parameter>recording-path</parameter> parameter will
- automatically be created if it does not yet exist. Only the
- final directory in the path will be created - if other
- directories earlier in the path do not exist, automatic
- creation will fail, and an error will be logged.</para>
- <para><emphasis>This parameter is optional.</emphasis> By
- default, the directory specified by the
- <parameter>recording-path</parameter> parameter will not
- automatically be created, and attempts to create recordings
- within a non-existent directory will be logged as
- errors.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-name</parameter></entry>
- <entry>
- <para>The filename to use for any created recordings.
- <emphasis>This parameter is optional.</emphasis> If
- omitted, the value "recording" will be used instead.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-output</parameter></entry>
- <entry>
- <para>If set to "true", graphical output and other data normally
- streamed from server to client will be excluded from the
- recording, producing a recording which contains only user
- input events. <emphasis>This parameter is
- optional.</emphasis> If omitted, graphical output will
- be included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-mouse</parameter></entry>
- <entry>
- <para>If set to "true", user mouse events will be excluded from
- the recording, producing a recording which lacks a visible
- mouse cursor. <emphasis>This parameter is
- optional.</emphasis> If omitted, mouse events will be
- included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-include-keys</parameter></entry>
- <entry>
- <para>If set to "true", user key events will be included in the
- recording. The recording can subsequently be passed through
- the <command>guaclog</command> utility to produce a
- human-readable interpretation of the keys pressed during the
- session. <emphasis>This parameter is optional.</emphasis> If
- omitted, key events will be not included in the
- recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-sftp">
- <title>File transfer (via SFTP)</title>
- <para>VNC does not normally support file transfer, but Guacamole can provide file
- transfer over SFTP even when the remote desktop is otherwise being accessed
- through VNC and not SSH. If SFTP is enabled on a Guacamole VNC connection, users
- will be able to upload and download files as described in <xref
- linkend="using-guacamole"/>.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>enable-sftp</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>file transfer</secondary>
- </indexterm><indexterm>
- <primary>SFTP</primary>
- </indexterm>Whether file transfer should be enabled. If set
- to "true", the user will be allowed to upload or download
- files from the specified server using SFTP. If omitted, SFTP
- will be disabled.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-hostname</parameter></entry>
- <entry>
- <para>The hostname or IP address of the server hosting SFTP.
- This parameter is optional. If omitted, the hostname of the
- VNC server specified with the
- <parameter>hostname</parameter> parameter will be
- used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-port</parameter></entry>
- <entry>
- <para>The port the SSH server providing SFTP is listening on,
- usually 22. This parameter is optional. If omitted, the
- standard port of 22 will be used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-host-key</parameter></entry>
- <entry>
- <para>The known hosts entry for the SFTP server. This
- parameter is optional, and, if not provided, no verification
- of SFTP host identity will be done. If the parameter is
- provided the identity of the server will be checked
- against the data.</para>
- <para>The format of this parameter should be that of a single
- entry from an OpenSSH <filename>known_hosts</filename>
- file.</para>
- <para>For more information, please see <xref linkend="ssh-host-verification"/>.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-username</parameter></entry>
- <entry>
- <para>The username to authenticate as when connecting to the
- specified SSH server for SFTP. This parameter is
- required.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-password</parameter></entry>
- <entry>
- <para>The password to use when authenticating with the specified
- SSH server for SFTP.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-private-key</parameter></entry>
- <entry>
- <para>The entire contents of the private key to use for public
- key authentication. If this parameter is not specified,
- public key authentication will not be used. The private key
- must be in OpenSSH format, as would be generated by the
- OpenSSH <command>ssh-keygen</command> utility.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-passphrase</parameter></entry>
- <entry>
- <para>The passphrase to use to decrypt the private key for use
- in public key authentication. This parameter is not needed
- if the private key does not require a passphrase.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-directory</parameter></entry>
- <entry>
- <para>The directory to upload files to if they are simply
- dragged and dropped, and thus otherwise lack a specific
- upload location. This parameter is optional. If omitted, the
- default upload location of the SSH server providing SFTP
- will be used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-root-directory</parameter></entry>
- <entry>
- <para>The directory to expose to connected users via Guacamole's
- <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="file-browser">file browser</link>. If omitted,
- the root directory will be used by default.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-server-alive-interval</parameter></entry>
- <entry>
- <para>The interval in seconds at which to send keepalive
- packets to the SSH server for the SFTP connection. This
- parameter is optional. If omitted, the default of 0 will be
- used, disabling sending keepalive packets. The minimum
- value is 2.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-disable-download</parameter></entry>
- <entry>
- <para>If set to true downloads from the remote system to
- the client (browser) will be disabled. The default is
- false, which means that downloads will be enabled.</para>
- <para>If sftp is not enabled, this parameter will be
- ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-disable-upload</parameter></entry>
- <entry>
- <para>If set to true uploads from the client (browser) to
- the remote system will be disabled. The default is
- false, which means that uploads will be enabled.</para>
- <para>If sftp is not enabled, this parameter will be
- ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-repeater">
- <title>VNC Repeater</title>
- <para>There exist VNC repeaters, such as UltraVNC Repeater, which act as
- intermediaries or proxies, providing a single logical VNC connection which is
- then routed to another VNC server elsewhere. Additional parameters are required
- to select which VNC host behind the repeater will receive the connection.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>dest-host</parameter></entry>
- <entry><indexterm>
- <primary>repeater</primary>
- <secondary>VNC</secondary>
- </indexterm><indexterm>
- <primary>proxy</primary>
- <secondary>VNC</secondary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>repeater</secondary>
- </indexterm>The destination host to request when connecting to a
- VNC proxy such as UltraVNC Repeater. This is only necessary if
- the VNC proxy in use requires the connecting user to specify
- which VNC server to connect to. If the VNC proxy automatically
- connects to a specific server, this parameter is not
- necessary.</entry>
- </row>
- <row>
- <entry><parameter>dest-port</parameter></entry>
- <entry><indexterm>
- <primary>repeater</primary>
- <secondary>VNC</secondary>
- </indexterm><indexterm>
- <primary>proxy</primary>
- <secondary>VNC</secondary>
- </indexterm>The destination port to request when connecting to a
- VNC proxy such as UltraVNC Repeater. This is only necessary if
- the VNC proxy in use requires the connecting user to specify
- which VNC server to connect to. If the VNC proxy automatically
- connects to a specific server, this parameter is not
- necessary.</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-reverse-connections">
- <title>Reverse VNC connections</title>
- <para>Guacamole supports "reverse" VNC connections, where the VNC client listens for
- an incoming connection from the VNC server. When reverse VNC connections are
- used, the VNC client and server switch network roles, but otherwise function as
- they normally would. The VNC server still provides the remote display, and the
- VNC client still provides all keyboard and mouse input.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>reverse-connect</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>reverse connection</secondary>
- </indexterm>Whether reverse connection should be used. If
- set to "true", instead of connecting to a server at a given
- hostname and port, guacd will listen on the given port for
- inbound connections from a VNC server.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>listen-timeout</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>listen timeout</secondary>
- </indexterm>If reverse connection is in use, the maximum
- amount of time to wait for an inbound connection from a VNC
- server, in milliseconds. If blank, the default value is 5000
- (five seconds).</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-audio">
- <title>Audio support (via PulseAudio)</title>
- <para>VNC does not provide its own support for audio, but Guacamole's VNC support
- can obtain audio through a secondary network connection to a PulseAudio server
- running on the same machine as the VNC server.</para>
- <para>Most Linux systems provide audio through a service called PulseAudio. This
- service is capable of communicating over the network, and if PulseAudio is
- configured to allow TCP connections, Guacamole can connect to your PulseAudio
- server and combine its audio with the graphics coming over VNC.</para>
- <para>Configuring PulseAudio for network connections requires an additional line
- within the PulseAudio configuration file, usually
- <filename>/etc/pulse/default.pa</filename>:</para>
- <informalexample>
- <programlisting>load-module module-native-protocol-tcp auth-ip-acl=<replaceable>192.168.1.0/24</replaceable> auth-anonymous=1</programlisting>
- </informalexample>
- <para>This loads the TCP module for PulseAudio, configuring it to accept connections
- without authentication and <emphasis>only</emphasis> from the
- <replaceable>192.168.1.0/24</replaceable> subnet. You will want to replace
- this value with the subnet or IP address from which guacd will be connecting. It
- is possible to allow connections from absolutely anywhere, but beware that you
- should only do so if the nature of your network prevents unauthorized
- access:</para>
- <informalexample>
- <programlisting>load-module module-native-protocol-tcp auth-anonymous=1</programlisting>
- </informalexample>
- <para>In either case, the <code>auth-anonymous=1</code> parameter is strictly
- required. Guacamole does not currently support the cookie-based authentication
- used by PulseAudio for non-anonymous connections. If this parameter is omitted,
- Guacamole will not be able to connect to PulseAudio.</para>
- <para>Once the PulseAudio configuration file has been modified appropriately,
- restart the PulseAudio service. PulseAudio should then begin listening on port
- 4713 (the default PulseAudio port) for incoming TCP connections. You can verify
- this using a utility like <command>netstat</command>:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>netstat -ln | grep 4713</userinput>
-<computeroutput>tcp 0 0 0.0.0.0:4713 0.0.0.0:* LISTEN
-tcp6 0 0 :::4713 :::* LISTEN</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>The following parameters are available for configuring the audio support for
- VNC:</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>enable-audio</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>VNC</primary>
- <secondary>sound</secondary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>PulseAudio</secondary>
- </indexterm>If set to "true", audio support will be enabled,
- and a second connection for PulseAudio will be made in
- addition to the VNC connection. By default, audio support
- within VNC is disabled.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>audio-servername</parameter></entry>
- <entry>
- <para>The name of the PulseAudio server to connect to. This will
- be the hostname of the computer providing audio for your
- connection via PulseAudio, most likely the same as the value
- given for the <parameter>hostname</parameter>
- parameter.</para>
- <para>If this parameter is omitted, the default PulseAudio
- device will be used, which will be the PulseAudio server
- running on the same machine as guacd.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-clipboard-encoding">
- <title>Clipboard encoding</title>
- <para>While Guacamole will always use UTF-8 for its own clipboard data, the VNC
- standard requires that clipboard data be encoded in ISO 8859-1. As most VNC
- servers will not accept data in any other format, Guacamole will translate
- between UTF-8 and ISO 8859-1 when exchanging clipboard data with the VNC server,
- but this behavior can be overridden with the
- <parameter>clipboard-encoding</parameter> parameter.</para>
- <important>
- <para><emphasis>The only clipboard encoding guaranteed to be supported by VNC
- servers is ISO 8859-1.</emphasis> You should only override the clipboard
- encoding using the <parameter>clipboard-encoding</parameter> parameter of
- you are absolutely positive your VNC server supports other encodings.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>clipboard-encoding</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>clipboard encoding</primary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>clipboard encoding</secondary>
- </indexterm>The encoding to assume for the VNC clipboard.
- This parameter is optionl. By default, the standard encoding
- ISO 8859-1 will be used. <emphasis>Only use this parameter
- if you are sure your VNC server supports other encodings
- beyond the standard ISO 8859-1.</emphasis></para>
- <para>Possible values are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>ISO8859-1</constant></term>
- <listitem>
- <para>ISO 8859-1 is the clipboard encoding mandated
- by the VNC standard, and supports only basic Latin
- characters. Unless your VNC server specifies
- otherwise, this encoding is the only encoding
- guaranteed to work.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>UTF-8</constant></term>
- <listitem>
- <para>UTF-8 - the most common encoding used for
- Unicode. Using this encoding for the VNC clipboard
- violates the VNC specification, but some servers
- do support this. This parameter value should only
- be used if you know your VNC server supports this
- encoding.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>UTF-16</constant></term>
- <listitem>
- <para>UTF-16 - a 16-bit encoding for Unicode which
- is not as common as UTF-8, but still widely used.
- Using this encoding for the VNC clipboard violates
- the VNC specification. This parameter value should
- only be used if you know your VNC server supports
- this encoding.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>CP1252</constant></term>
- <listitem>
- <para>Code page 1252 - a Windows-specific encoding
- for Latin characters which is mostly a superset of
- ISO 8859-1, mapping some additional displayable
- characters onto what would otherwise be control
- characters. Using this encoding for the VNC
- clipboard violates the VNC specification. This
- parameter value should only be used if you know
- your VNC server supports this encoding.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-disable-clipboard">
- <title>Disabling clipboard access</title>
- <para>Guacamole provides bidirectional access to the clipboard by default for VNC
- connections. This behavior can be overridden on a per-connection basis with the
- <parameter>disable-copy</parameter> and <parameter>disable-paste</parameter>
- parameters.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>disable-copy</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>disable clipboard</primary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>disable clipboard</secondary>
- </indexterm>If set to "true", text copied within the VNC
- session will not be accessible by the user at the browser
- side of the Guacamole session, and will be usable only
- within the remote desktop. This parameter is optional. By
- default, the user will be given access to the copied
- text.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-paste</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>disable clipboard</primary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>disable clipboard</secondary>
- </indexterm>If set to "true", text copied at the browser
- side of the Guacamole session will not be accessible within
- the VNC session. This parameter is optional. By default, the
- user will be able to paste data from outside the browser
- within the VNC session.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="vnc-wake-on-lan">
- <title>Wake-on-LAN Configuration</title>
- <para>Guacamole implements the support to send a "magic wake-on-lan
- packet" to a remote host prior to attempting to establish a
- connection with the host. The below parameters control the
- behavior of this functionality, which is disabled by default.
- </para>
- <important>
- <para>There are several factors that can impact the ability
- of Wake-on-LAN (WoL) to function correctly, many of which
- are outside the scope of Guacamole configuration. If you
- are configuring WoL within Guacamole you should also be
- familiar with the other components that need to be
- configured in order for it to function correctly.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>VNC</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>wol-send-packet</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-send-packet</primary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>wol-send-packet</secondary>
- </indexterm>If set to "true", Guacamole will
- attempt to send the Wake-On-LAN packet prior
- to establishing a connection. This parameter
- is optional. By default, Guacamole will
- not send the WoL packet. Enabling this
- option requires that the
- <parameter>wol-mac-addr</parameter>
- parameter also be configured, otherwise
- the WoL packet will not be sent.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-mac-addr</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-mac-addr</primary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>wol-mac-addr</secondary>
- </indexterm>This parameter configures the
- MAC address that Guacamole will use in
- the magic WoL packet to attempt to wake
- the remote system. If
- <parameter>wol-send-packet</parameter>
- is enabled, this parameter is required
- or else the WoL packet will not be sent.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-broadcast-addr</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-broadcast-addr</primary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>wol-broadcast-addr</secondary>
- </indexterm>This parameter configures the
- IPv4 broadcast address or IPv6 multicast
- address that Guacamole will send the
- WoL packet to in order to wake the host.
- This parameter is optional. If no value
- is provided, the default local IPv4 broadcast
- address (255.255.255.255) will be used.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-udp-port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-udp-port</primary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>wol-udp-port</secondary>
- </indexterm>This parameter configures the
- UDP port that will be set in the WoL packet.
- In most cases the UDP port isn't processed
- by the system that will be woken up; however,
- there are certain cases where it is useful
- for the port to be set, as in situations
- where a router is listening for the packet
- and can make routing decisions depending
- upon the port that is used. If not
- configured the default UDP port 9 will be
- used.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-wait-time</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-wait-time</primary>
- </indexterm><indexterm>
- <primary>VNC</primary>
- <secondary>wol-wait-time</secondary>
- </indexterm>By default after the WoL packet
- is sent Guacamole will attempt immediately
- to connect to the remote host. It may be
- desirable in certain scenarios to have
- Guacamole wait before the initial connection
- in order to give the remote system time to
- boot. Setting this parameter to a positive
- value will cause Guacamole to wait the specified
- number of seconds before attempting the initial
- connection. This parameter is optional.
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="adding-vnc">
- <title>Adding a VNC connection</title>
- <indexterm>
- <primary>VNC</primary>
- <secondary>adding</secondary>
- </indexterm>
- <para>If you are using the default authentication built into Guacamole, and you wish
- to grant access to a VNC connection to a particular user, you need to locate the
- <code><authorize></code> section for that user within your
- <filename>user-mapping.xml</filename>, and add a section like the following
- within it:</para>
- <programlisting><connection name="<replaceable>Unique Name</replaceable>">
- <protocol>vnc</protocol>
- <param name="hostname"><replaceable>localhost</replaceable></param>
- <param name="port"><replaceable>5901</replaceable></param>
-</connection></programlisting>
- <para>If added exactly as above, a new connection named "<replaceable>Unique
- Name</replaceable>" will be available to the user associated with the
- <code><authorize></code> section containing it. The connection will use
- VNC to connect to <replaceable>localhost</replaceable> at port
- <replaceable>5901</replaceable>. Naturally, you will want to change some or
- all of these values.</para>
- <para>If your VNC server requires a password, or you wish to specify other
- configuration parameters (to reduce the color depth, for example), you will need
- to add additional <code><param></code> tags accordingly.</para>
- <para>Other authentication methods will provide documentation describing how to
- configure new connections. If the authentication method in use fully implements
- the features of Guacamole's authentication API, you will be able to add a new
- VNC connection easily and intuitively using the administration interface built
- into Guacamole. You will not need to edit configuration files.</para>
- </section>
- <section xml:id="vnc-servers">
- <title>Which VNC server?</title>
- <indexterm>
- <primary>VNC servers</primary>
- </indexterm>
- <para>The choice of VNC server can make a big difference when it comes to
- performance, especially over slower networks. While many systems provide VNC
- access by default, using this is often not the fastest method.</para>
- <section xml:id="realvnc">
- <title>RealVNC or TigerVNC</title>
- <indexterm>
- <primary>RealVNC</primary>
- </indexterm>
- <indexterm>
- <primary>TigerVNC</primary>
- </indexterm>
- <para>RealVNC, and its derivative TigerVNC, perform quite well. In our testing,
- they perform the best with Guacamole. If you are okay with having a desktop
- that can only be accessed via VNC, one of these is likely your best choice.
- Both optimize window movement and (depending on the application) scrolling,
- giving a very responsive user experience.</para>
- </section>
- <section xml:id="tightvnc">
- <title>TightVNC</title>
- <indexterm>
- <primary>TightVNC</primary>
- </indexterm>
- <para>TightVNC is widely-available and performs generally as well as RealVNC or
- TigerVNC. If you wish to use TightVNC with Guacamole, performance should be
- just fine, but we highly recommend disabling its JPEG encoding. This is
- because images transmitted to Guacamole are always encoded losslessly as PNG
- images. When this operation is performed on a JPEG image, the artifacts
- present from JPEG's lossy compression reduce the compressibility of the
- image for PNG, thus leading to a slower experience overall than if JPEG was
- simply not used to begin with.</para>
- </section>
- <section xml:id="x11vnc">
- <title>x11vnc</title>
- <indexterm>
- <primary>x11vnc</primary>
- </indexterm>
- <para>The main benefit of using x11vnc is that it allows you to continue using
- your desktop normally, while simultaneously exposing control of your desktop
- via VNC. Performance of x11vnc is comparable to RealVNC, TigerVNC, and
- TightVNC. If you need to use your desktop locally as well as via VNC, you
- will likely be quite happy with x11vnc.</para>
- </section>
- <section xml:id="vino">
- <title>vino</title>
- <indexterm>
- <primary>vino</primary>
- </indexterm>
- <para>vino is the VNC server that comes with the Gnome desktop environment, and
- is enabled if you enable "desktop sharing" via the system preferences
- available within Gnome. If you need to share your local desktop, we
- recommend using x11vnc rather vino, as it has proven more performant and
- feature-complete in our testing. If you don't need to share a local desktop
- but simply need an environment you can access remotely, using a VNC server
- like RealVNC, TigerVNC, or TightVNC is a better choice.</para>
- </section>
- <section xml:id="qemu">
- <title>QEMU or KVM</title>
- <indexterm>
- <primary>QEMU</primary>
- </indexterm>
- <indexterm>
- <primary>KVM</primary>
- </indexterm>
- <para>QEMU (and thus KVM) expose the displays of virtual machines using VNC. If
- you need to see the virtual monitor of your virtual machine, using this VNC
- connection is really your only choice. As the VNC server built into QEMU
- cannot be aware of higher-level operations like window movement, resizing,
- or scrolling, those operations will tend to be sent suboptimally, and will
- not be as fast as a VNC server running within the virtual machine.</para>
- <para>If you wish to use a virtual machine for desktop access, we recommend
- installing a native VNC server inside the virtual machine after the virtual
- machine is set up. This will give a more responsive desktop.</para>
- </section>
- </section>
- </section>
- <section xml:id="rdp">
- <title>RDP</title>
- <indexterm>
- <primary>RDP</primary>
- </indexterm>
- <para>The RDP protocol is more complicated than VNC and was the second protocol
- officially supported by Guacamole. RDP tends to be faster than VNC due to the use of
- caching, which Guacamole does take advantage of.</para>
- <para>RDP support for Guacamole is provided by the <package>libguac-client-rdp</package>
- library, which will be installed as part of guacamole-server if the required
- dependencies are present during the build.</para>
- <section xml:id="rdp-network-parameters">
- <title>Network parameters</title>
- <para>RDP connections require a hostname or IP address defining the destination
- machine. The RDP port is defined to be 3389, and will be this value in most
- cases. You only need to specify the RDP port if you are not using port
- 3389.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>hostname</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>hostname</secondary>
- </indexterm>The hostname or IP address of the RDP server
- Guacamole should connect to.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>port</secondary>
- </indexterm>The port the RDP server is listening on. This
- parameter is optional. If this is not specified, the
- standard port for RDP (3389) or Hyper-V's default port for
- VMConnect (2179) will be used, depending on the security
- mode selected.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-authentication">
- <title>Authentication and security</title>
- <para>RDP provides authentication through the use of a username, password, and
- optional domain. All RDP connections are encrypted.</para>
- <para>Most RDP servers will provide a graphical login if the username, password, and
- domain parameters are omitted. One notable exception to this is Network Level
- Authentication, or NLA, which performs all authentication outside of a desktop
- session, and thus in the absence of a graphical interface.</para>
- <para>Servers that require NLA can be handled by Guacamole in one of two ways. The
- first is to provide the username and password within the connection
- configuration, either via static values or by passing through the Guacamole
- credentials with <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="parameter-tokens">parameter tokens</link> and
- <link xmlns:xlink="http://www.w3.org/1999/xlink" linkend="ldap-auth">
- LDAP support</link>. Alternatively, if credentials are not configured
- within the connection configuration, Guacamole will attempt to prompt the user
- for the credentials interactively, if the versions of both guacd and
- Guacamole Client in use support it. If either component does not support
- prompting and the credentials are not configured, NLA-based connections will
- fail.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>username</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>username</secondary>
- </indexterm>The username to use to authenticate, if any.
- This parameter is optional.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>password</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>password</secondary>
- </indexterm>The password to use when attempting
- authentication, if any. This parameter is optional.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>domain</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>domain</secondary>
- </indexterm>The domain to use when attempting
- authentication, if any. This parameter is optional.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>security</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>security</secondary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>NLA</secondary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>TLS</secondary>
- </indexterm>The security mode to use for the RDP connection.
- This mode dictates how data will be encrypted and what type
- of authentication will be performed, if any. By default, a
- security mode is selected based on a negotiation process
- which determines what both the client and the server
- support.</para>
- <para>Possible values are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>any</constant></term>
- <listitem>
- <para>Automatically select the security mode based
- on the security protocols supported by both the
- client and the server. <emphasis>This is the
- default</emphasis>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>nla</constant></term>
- <listitem>
- <para>Network Level Authentication, sometimes also
- referred to as "hybrid" or CredSSP (the protocol
- that drives NLA). This mode uses TLS encryption
- and requires the username and password to be given
- in advance. Unlike RDP mode, the authentication
- step is performed before the remote desktop
- session actually starts, avoiding the need for the
- Windows server to allocate significant resources
- for users that may not be authorized.</para>
- <para>If the versions of guacd and Guacamole Client
- in use support prompting and the username, password,
- and domain are not specified, the user will be
- interactively prompted to enter credentials to
- complete NLA and continue the connection. Otherwise,
- when prompting is not supported and credentials are
- not provided, NLA connections will fail.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>nla-ext</constant></term>
- <listitem>
- <para>Extended Network Level Authentication. This
- mode is identical to NLA except that an additional
- "<link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/d0e560a3-25cb-4563-8bdc-6c4cc625bbfc"
- >Early User Authorization Result</link>" is
- required to be sent from the server to the client
- immediately after the NLA handshake is
- completed.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>tls</constant></term>
- <listitem>
- <para>RDP authentication and encryption implemented
- via TLS (Transport Layer Security). Also referred
- to as RDSTLS, the TLS security mode is primarily
- used in load balanced configurations where the
- initial RDP server may redirect the connection to
- a different RDP server.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>vmconnect</constant></term>
- <listitem>
- <para>Automatically select the security mode based
- on the security protocols supported by both the
- client and the server, limiting that negotiation
- to only the protocols known to be supported by
- <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="rdp-preconnection-pdu">Hyper-V /
- VMConnect</link>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>rdp</constant></term>
- <listitem>
- <para>Standard RDP encryption. This mode is
- generally only used for older Windows servers or
- in cases where a standard Windows login screen is
- desired. Newer versions of Windows have this mode
- disabled by default and will only accept NLA
- unless explicitly configured otherwise.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </entry>
- </row>
- <row>
- <entry><parameter>ignore-cert</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>ignoring certificates</secondary>
- </indexterm>If set to "true", the certificate returned by
- the server will be ignored, even if that certificate cannot
- be validated. This is useful if you universally trust the
- server and your connection to the server, and you know that
- the server's certificate cannot be validated (for example,
- if it is self-signed).</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-auth</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>disabling authentication</secondary>
- </indexterm>If set to "true", authentication will be
- disabled. Note that this refers to authentication that takes
- place while connecting. Any authentication enforced by the
- server over the remote desktop session (such as a login
- dialog) will still take place. By default, authentication is
- enabled and only used when requested by the server.</para>
- <para>If you are using NLA, authentication must be enabled by
- definition.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-session-settings">
- <title>Session settings</title>
- <para>RDP sessions will typically involve the full desktop environment of a normal
- user. Alternatively, you can manually specify a program to use instead of the
- RDP server's default shell, or connect to the administrative console.</para>
- <para>Although Guacamole is independent of keyboard layout, RDP is not. This is
- because Guacamole represents keys based on what they <emphasis>do</emphasis>
- ("press the <keycap>Enter</keycap> key"), while RDP uses identifiers based on
- the key's location ("press the rightmost key in the second row"). To translate
- between a Guacamole key event and an RDP key event, Guacamole must know ahead
- of time the keyboard layout of the RDP server.</para>
- <para>By default, the US English qwerty keyboard will be used. If this does not
- match the keyboard layout of your RDP server, keys will not be properly
- translated, and you will need to explicitly choose a different layout in your
- connection settings. If your keyboard layout is not supported, please notify the
- Guacamole team by <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://issues.apache.org/jira/browse/GUACAMOLE">opening an issue in
- JIRA</link>.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>client-name</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>client-name</secondary>
- </indexterm>When connecting to the RDP server, Guacamole
- will normally provide its own hostname as the name of the
- client. If this parameter is specified, Guacamole will use
- its value instead.</para>
- <para>On Windows RDP servers, this value is exposed within the
- session as the <envar>CLIENTNAME</envar> environment
- variable.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>console</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>console</secondary>
- </indexterm>If set to "true", you will be connected to the
- console (admin) session of the RDP server.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>initial-program</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>initial program</secondary>
- </indexterm>The full path to the program to run immediately
- upon connecting. This parameter is optional.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>server-layout</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>keyboard layout</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>keyboard layout</secondary>
- </indexterm>The server-side keyboard layout. This is the
- layout of the RDP server and has nothing to do with the
- keyboard layout in use on the client. <emphasis>The
- Guacamole client is independent of keyboard
- layout.</emphasis> The RDP protocol, however, is
- <emphasis>not</emphasis> independent of keyboard layout,
- and Guacamole needs to know the keyboard layout of the
- server in order to send the proper keys when a user is
- typing.</para>
- <para>Possible values are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>en-us-qwerty</constant></term>
- <listitem>
- <para>English (US) keyboard</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>en-gb-qwerty</constant></term>
- <listitem>
- <para>English (UK) keyboard</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>de-ch-qwertz</constant></term>
- <listitem>
- <para>Swiss German keyboard (qwertz)</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>de-de-qwertz</constant></term>
- <listitem>
- <para>German keyboard (qwertz)</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>fr-be-azerty</constant></term>
- <listitem>
- <para>Belgian French keyboard (azerty)</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>fr-fr-azerty</constant></term>
- <listitem>
- <para>French keyboard (azerty)</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>fr-ch-qwertz</constant></term>
- <listitem>
- <para>Swiss French keyboard (qwertz)</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>hu-hu-qwertz</constant></term>
- <listitem>
- <para>Hungarian keyboard (qwertz)</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>it-it-qwerty</constant></term>
- <listitem>
- <para>Italian keyboard</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>ja-jp-qwerty</constant></term>
- <listitem>
- <para>Japanese keyboard</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>pt-br-qwerty</constant></term>
- <listitem>
- <para>Portuguese Brazilian keyboard</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>es-es-qwerty</constant></term>
- <listitem>
- <para>Spanish keyboard</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>es-latam-qwerty</constant></term>
- <listitem>
- <para>Latin American keyboard</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>sv-se-qwerty</constant></term>
- <listitem>
- <para>Swedish keyboard</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>tr-tr-qwerty</constant></term>
- <listitem>
- <para>Turkish-Q keyboard</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>failsafe</constant></term>
- <listitem>
- <para>Unknown keyboard - this option sends only
- Unicode events and should work for any keyboard,
- though not necessarily all RDP servers or
- applications.</para>
- <para>If your server's keyboard layout is not yet
- supported, this option should work in the
- meantime.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </entry>
- </row>
- <row>
- <entry><parameter>timezone</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>timezone</secondary>
- </indexterm>The timezone that the client
- should send to the server for configuring the
- local time display of that server. The
- format of the timezone is in the standard
- IANA key zone format, which is the format
- used in UNIX/Linux. This will be converted
- by RDP into the correct format for Windows.
- </para>
- <para>The timezone is detected and will be
- passed to the server during the handshake
- phase of the connection, and may used by
- protocols, like RDP, that support it. This
- parameter can be used to override the value
- detected and passed during the handshake, or
- can be used in situations where guacd does
- not support passing the timezone parameter
- during the handshake phase (guacd versions
- prior to 1.3.0).</para>
- <para>Support for forwarding the client
- timezone varies by RDP server implementation.
- For example, with Windows, support for
- forwarding timezones is only present in
- Windows Server with Remote Desktop Services
- (RDS, formerly known as Terminal Services)
- installed. Windows Server installations in
- admin mode, along with Windows workstation
- versions, do not allow the timezone to be
- forwarded. Other server implementations,
- for example, xrdp, may not implement this
- feature at all. Consult the documentation
- for the RDP server to determine whether or
- not this feature is supported.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-display-settings">
- <title>Display settings</title>
- <para>Guacamole will automatically choose an appropriate display size for RDP
- connections based on the size of the browser window and the DPI of the device.
- The size of the display can be forced by specifying explicit width or height
- values.</para>
- <para>To reduce bandwidth usage, you may also request that the server reduce its
- color depth. Guacamole will automatically detect 256-color images, but this can
- be guaranteed for absolutely all graphics sent over the connection by forcing
- the color depth to 8-bit. Color depth is otherwise dictated by the RDP
- server.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>color-depth</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>color depth</secondary>
- </indexterm>The color depth to request, in bits-per-pixel.
- This parameter is optional. If specified, this must be
- either 8, 16, or 24. Regardless of what value is chosen
- here, if a particular update uses less than 256 colors,
- Guacamole will always send that update as a 256-color
- PNG.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>width</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>display size</secondary>
- </indexterm>The width of the display to request, in pixels.
- This parameter is optional. If this value is not specified,
- the width of the connecting client display will be used
- instead.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>height</parameter></entry>
- <entry>
- <para>The height of the display to request, in pixels. This
- parameter is optional. If this value is not specified, the
- height of the connecting client display will be used
- instead.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>dpi</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>display resolution</secondary>
- </indexterm>The desired effective resolution of the client
- display, in DPI. This parameter is optional. If this value
- is not specified, the resolution and size of the client
- display will be used together to determine, heuristically,
- an appropriate resolution for the RDP session.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>resize-method</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>display size</secondary>
- </indexterm>The method to use to update the RDP server when
- the width or height of the client display changes. This
- parameter is optional. If this value is not specified, no
- action will be taken when the client display changes
- size.</para>
- <para>Normally, the display size of an RDP session is constant
- and can only be changed when initially connecting. As of RDP
- 8.1, the "Display Update" channel can be used to request
- that the server change the display size. For older RDP
- servers, the only option is to disconnect and reconnect with
- the new size.</para>
- <para>Possible values are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>display-update</constant></term>
- <listitem>
- <para>Uses the "Display Update" channel added with
- RDP 8.1 to signal the server when the client
- display size has changed.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>reconnect</constant></term>
- <listitem>
- <para>Automatically disconnects the RDP session when
- the client display size has changed, and
- reconnects with the new size.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </entry>
- </row>
- <row>
- <entry><parameter>force-lossless</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>lossless compression</secondary>
- </indexterm>Whether this connection should only use lossless
- compression for graphical updates. If set to "true", lossy
- compression will not be used. This parameter is optional. By
- default, lossy compression will be used when heuristics
- determine that it would likely outperform lossless
- compression.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-recording">
- <title>Session recording</title>
- <para>RDP sessions can be recorded graphically. These recordings take the form of
- Guacamole protocol dumps and are recorded automatically to a specified
- directory. Recordings can be subsequently translated to a normal video stream
- using the <command>guacenc</command> utility provided with
- guacamole-server.</para>
- <para>For example, to produce a video called "<replaceable>NAME</replaceable>.m4v"
- from the recording "<replaceable>NAME</replaceable>", you would run:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guacenc <replaceable>/path/to/recording/NAME</replaceable></userinput></screen>
- </informalexample>
- <para>The <command>guacenc</command> utility has additional options for overriding
- default behavior, including tweaking the output format, which are documented in
- detail within the manpage:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>man guacenc</userinput></screen>
- </informalexample>
- <para>If recording of key events is explicitly enabled using the
- <parameter>recording-include-keys</parameter> parameter, recordings can also
- be translated into human-readable interpretations of the keys pressed during the
- session using the <command>guaclog</command> utility. The usage of
- <command>guaclog</command> is analogous to <command>guacenc</command>, and
- results in the creation of a new text file containing the interpreted
- events:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guaclog <replaceable>/path/to/recording/NAME</replaceable></userinput><computeroutput>
-guaclog: INFO: Guacamole input log interpreter (guaclog) version 1.3.0
-guaclog: INFO: 1 input file(s) provided.
-guaclog: INFO: Writing input events from "<replaceable>/path/to/recording/NAME</replaceable>" to "<replaceable annotations="">/path/to/recording/NAME</replaceable>.txt" ...
-guaclog: INFO: All files interpreted successfully.</computeroutput>
-<prompt>$</prompt> </screen>
- </informalexample>
- <important>
- <para>Guacamole will never overwrite an existing recording. If necessary, a
- numeric suffix like ".1", ".2", ".3", etc. will be appended to
- <replaceable>NAME</replaceable> to avoid overwriting an existing
- recording. If even appending a numeric suffix does not help, the session
- will simply not be recorded.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>recording-path</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>graphical recording</secondary>
- </indexterm>The directory in which screen recording files
- should be created. <emphasis>If a graphical recording needs
- to be created, then this parameter is
- required.</emphasis> Specifying this parameter enables
- graphical screen recording. If this parameter is omitted, no
- graphical recording will be created.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>create-recording-path</parameter></entry>
- <entry>
- <para>If set to "true", the directory specified by the
- <parameter>recording-path</parameter> parameter will
- automatically be created if it does not yet exist. Only the
- final directory in the path will be created - if other
- directories earlier in the path do not exist, automatic
- creation will fail, and an error will be logged.</para>
- <para><emphasis>This parameter is optional.</emphasis> By
- default, the directory specified by the
- <parameter>recording-path</parameter> parameter will not
- automatically be created, and attempts to create recordings
- within a non-existent directory will be logged as
- errors.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-name</parameter></entry>
- <entry>
- <para>The filename to use for any created recordings.
- <emphasis>This parameter is optional.</emphasis> If
- omitted, the value "recording" will be used instead.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-output</parameter></entry>
- <entry>
- <para>If set to "true", graphical output and other data normally
- streamed from server to client will be excluded from the
- recording, producing a recording which contains only user
- input events. <emphasis>This parameter is
- optional.</emphasis> If omitted, graphical output will
- be included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-mouse</parameter></entry>
- <entry>
- <para>If set to "true", user mouse events will be excluded from
- the recording, producing a recording which lacks a visible
- mouse cursor. <emphasis>This parameter is
- optional.</emphasis> If omitted, mouse events will be
- included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-include-keys</parameter></entry>
- <entry>
- <para>If set to "true", user key events will be included in the
- recording. The recording can subsequently be passed through
- the <command>guaclog</command> utility to produce a
- human-readable interpretation of the keys pressed during the
- session. <emphasis>This parameter is optional.</emphasis> If
- omitted, key events will be not included in the
- recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-device-redirection">
- <title>Device redirection</title>
- <para>Device redirection refers to the use of non-display devices over RDP.
- Guacamole's RDP support currently allows redirection of audio, printing, and
- disk access, some of which require additional configuration in order to function
- properly.</para>
- <para>Audio redirection will be enabled by default. If Guacamole was correctly
- installed, and audio redirection is supported by your RDP server, sound should
- play within remote connections without manual intervention.</para>
- <para>Printing requires <application>GhostScript</application> to be installed on
- the Guacamole server, and allows users to print arbitrary documents directly to
- PDF. When documents are printed to the redirected printer, the user will receive
- a PDF of that document within their web browser.</para>
- <para>Guacamole provides support for file transfer over RDP by emulating a virtual
- disk drive. This drive will persist on the Guacamole server, confined within the
- drive path specified. If drive redirection is enabled on a Guacamole SSH
- connection, users will be able to upload and download files as described in
- <xref linkend="using-guacamole"/>.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>disable-audio</parameter></entry>
- <entry><indexterm>
- <primary>disabling audio</primary>
- </indexterm><indexterm>
- <primary>audio</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>audio</secondary>
- </indexterm>Audio is enabled by default in both the client and
- in libguac-client-rdp. If you are concerned about bandwidth
- usage, or sound is causing problems, you can explicitly disable
- sound by setting this parameter to "true".</entry>
- </row>
- <row>
- <entry><parameter>enable-audio-input</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>enabling audio input</primary>
- </indexterm><indexterm>
- <primary>audio input</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>audio input</secondary>
- </indexterm>If set to "true", audio input support
- (microphone) will be enabled, leveraging the standard
- "AUDIO_INPUT" channel of RDP. By default, audio input
- support within RDP is disabled.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>enable-printing</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>enabling printing</primary>
- </indexterm><indexterm>
- <primary>printing</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>printing</secondary>
- </indexterm>Printing is disabled by default, but with
- printing enabled, RDP users can print to a virtual printer
- that sends a PDF containing the document printed to the
- Guacamole client. Enable printing by setting this parameter
- to "true".</para>
- <para><emphasis>Printing support requires
- <application>GhostScript</application> to be
- installed.</emphasis> If
- <application>guacd</application> cannot find the
- <filename>gs</filename> executable when printing, the
- print attempt will fail.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>printer-name</parameter></entry>
- <entry>
- <para>The name of the redirected printer device that is passed
- through to the RDP session. This is the name that the user
- will see in, for example, the Devices and Printers control
- panel.</para>
- <para>If printer redirection is not enabled, this option has no
- effect.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>enable-drive</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>enabling file transfer</primary>
- </indexterm><indexterm>
- <primary>file transfer</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>file transfer</secondary>
- </indexterm>File transfer is disabled by default, but with
- file transfer enabled, RDP users can transfer files to and
- from a virtual drive which persists on the Guacamole server.
- Enable file transfer support by setting this parameter to
- "true".</para>
- <para>Files will be stored in the directory specified by the
- "<parameter>drive-path</parameter>" parameter, which is
- required if file transfer is enabled.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-download</parameter></entry>
- <entry>
- <para>If set to true downloads from the remote server to
- client (browser) will be disabled. This includes both
- downloads down via the hidden Guacamole menu, as well
- as using the special "Download" folder presented to
- the remote server. The default is false, which means
- that downloads will be allowed.</para>
- <para>If file transfer is not enabled, this parameter is
- ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-upload</parameter></entry>
- <entry>
- <para>If set to true, uploads from the client (browser)
- to the remote server location will be disabled. The
- default is false, which means uploads will be allowed
- if file transfer is enabled.</para>
- <para>If file transfer is not enabled, this parameter is
- ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>drive-name</parameter></entry>
- <entry>
- <para>The name of the filesystem used when passed through to
- the RDP session. This is the name that users will see in their
- Computer/My Computer area along with client name (for example,
- "Guacamole on Guacamole RDP"), and is also the name of the share
- when accessing the special <filename>\\tsclient</filename>
- network location.</para>
- <para>If file transfer is not enabled, this parameter is
- ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>drive-path</parameter></entry>
- <entry>
- <para>The directory on the Guacamole server in which transferred
- files should be stored. This directory must be accessible by
- guacd and both readable and writable by the user that runs
- guacd. <emphasis>This parameter does not refer to a
- directory on the RDP server.</emphasis></para>
- <para>If file transfer is not enabled, this parameter is
- ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>create-drive-path</parameter></entry>
- <entry>
- <para>If set to "true", and file transfer is enabled, the
- directory specified by the <parameter>drive-path</parameter>
- parameter will automatically be created if it does not yet
- exist. Only the final directory in the path will be created
- - if other directories earlier in the path do not exist,
- automatic creation will fail, and an error will be
- logged.</para>
- <para>By default, the directory specified by the
- <parameter>drive-path</parameter> parameter will not
- automatically be created, and attempts to transfer files to
- a non-existent directory will be logged as errors.</para>
- <para>If file transfer is not enabled, this parameter is
- ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>console-audio</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>console audio</secondary>
- </indexterm>If set to "true", audio will be explicitly
- enabled in the console (admin) session of the RDP server.
- Setting this option to "true" only makes sense if the
- <parameter>console</parameter> parameter is also set to
- "true".</para>
- </entry>
- </row>
- <row>
- <entry><parameter>static-channels</parameter></entry>
- <entry>
- <para>A comma-separated list of static channel names to open and
- expose as pipes. If you wish to communicate between an
- application running on the remote desktop and JavaScript,
- this is the best way to do it. Guacamole will open an
- outbound pipe with the name of the static channel. If
- JavaScript needs to communicate back in the other direction,
- it should respond by opening another pipe with the same
- name.</para>
- <para>Guacamole allows any number of static channels to be
- opened, but protocol restrictions of RDP limit the size of
- each channel name to 7 characters.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-preconnection-pdu">
- <title>Preconnection PDU (Hyper-V / VMConnect)</title>
- <para><indexterm>
- <primary>preconnection PDU</primary>
- </indexterm><indexterm>
- <primary>Hyper-V</primary>
- </indexterm><indexterm>
- <primary>VMConnect</primary>
- </indexterm>Some RDP servers host multiple logical RDP connections behind a
- single server listening on a single TCP port. To select between these logical
- connections, an RDP client must send the "preconnection PDU" - a message which
- contains values that uniquely identify the destination, referred to as the "RDP
- source". This mechanism is defined by the <link
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://msdn.microsoft.com/en-us/library/cc242359.aspx">"Session
- Selection Extension"</link> for the RDP protocol, and is implemented by
- Microsoft's Hyper-V hypervisor.</para>
- <para>If you are using Hyper-V, you will need to specify the ID of the destination
- virtual machine within the <parameter>preconnection-blob</parameter> parameter.
- This value can be determined using PowerShell:</para>
- <informalexample>
- <screen><computeroutput><prompt>PS C:\> </prompt></computeroutput><userinput>Get-VM <replaceable>VirtualMachineName</replaceable> | Select-Object Id
-</userinput><computeroutput>
-Id
---
-ed272546-87bd-4db9-acba-e36e1a9ca20a
-
-
-<prompt>PS C:\> </prompt></computeroutput></screen>
- </informalexample>
- <para>The preconnection PDU is intentionally generic. While its primary use is as a
- means for selecting virtual machines behind Hyper-V, other RDP servers may use
- it as well. It is up to the RDP server itself to determine whether the
- preconnection ID, BLOB, or both will be used, and what their values mean.</para>
- <para><emphasis>If you do intend to use Hyper-V, beware that its built-in RDP server
- requires different parameters for authentication and Guacamole's defaults
- will not work.</emphasis> In most cases, you will need to do the following
- when connecting to Hyper-V:</para>
- <orderedlist>
- <listitem>
- <para>Specify both "<parameter>username</parameter>" and
- "<parameter>password</parameter>" appropriately, and set
- "<parameter>security</parameter>" to
- "<constant>vmconnect</constant>". Selecting the
- "<constant>vmconnect</constant>" security mode will configure
- Guacamole to automatically negotiate security modes known to be
- supported by Hyper-V, and will automatically select Hyper-V's default
- RDP port (2179).</para>
- </listitem>
- <listitem>
- <para>If necessary, set "<parameter>ignore-cert</parameter>" to
- "<constant>true</constant>". Hyper-V may use a self-signed
- certificate.</para>
- </listitem>
- </orderedlist>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>preconnection-id</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>preconnection ID</primary>
- </indexterm>The numeric ID of the RDP source. This is a
- non-negative integer value dictating which of potentially
- several logical RDP connections should be used. This
- parameter is optional, and is only required if the RDP
- server is documented as requiring it. <emphasis>If using
- Hyper-V, this should be left blank.</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><parameter>preconnection-blob</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>preconnection BLOB</primary>
- </indexterm><indexterm>
- <primary>Hyper-V</primary>
- </indexterm>An arbitrary string which identifies the RDP
- source - one of potentially several logical RDP connections
- hosted by the same RDP server. This parameter is optional,
- and is only required if the RDP server is documented as
- requiring it, such as Hyper-V. In all cases, the meaning of
- this parameter is opaque to the RDP protocol itself and is
- dictated by the RDP server. <emphasis>For Hyper-V, this will
- be the ID of the destination virtual
- machine.</emphasis></para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-gateway">
- <title>Remote desktop gateway</title>
- <para><indexterm>
- <primary>remote desktop gateway</primary>
- </indexterm><indexterm>
- <primary>TS gateway</primary>
- </indexterm>Microsoft's remote desktop server provides an additional gateway
- service which allows external connections to be forwarded to internal RDP
- servers which are otherwise not accessible. If you will be using Guacamole to
- connect through such a gateway, you will need to provide additional parameters
- describing the connection to that gateway, as well as any required
- credentials.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>gateway-hostname</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>gateway hostname</primary>
- </indexterm>The hostname of the remote desktop gateway that
- should be used as an intermediary for the remote desktop
- connection. <emphasis>If omitted, a gateway will not be
- used.</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><parameter>gateway-port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>gateway port</primary>
- </indexterm>The port of the remote desktop gateway that
- should be used as an intermediary for the remote desktop
- connection. By default, this will be "443".</para>
- </entry>
- </row>
- <row>
- <entry><parameter>gateway-username</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>gateway username</primary>
- </indexterm>The username of the user authenticating with the
- remote desktop gateway, if a gateway is being used. This is
- not necessarily the same as the user actually using the
- remote desktop connection.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>gateway-password</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>gateway password</primary>
- </indexterm>The password to provide when authenticating with
- the remote desktop gateway, if a gateway is being
- used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>gateway-domain</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>gateway domain</primary>
- </indexterm>The domain of the user authenticating with the
- remote desktop gateway, if a gateway is being used. This is
- not necessarily the same domain as the user actually using
- the remote desktop connection.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-connection-broker">
- <title>Load balancing and RDP connection brokers</title>
- <para><indexterm>
- <primary>load balancing</primary>
- </indexterm><indexterm>
- <primary>connection broker</primary>
- </indexterm>If your remote desktop servers are behind a load balancer, sometimes
- referred to as a "connection broker" or "TS session broker", that balancer may
- require additional information during the connection process to determine how
- the incoming connection should be routed. RDP does not dictate the format of
- this information; it is specific to the balancer in use.</para>
- <para>If you are using a load balancer and are unsure whether such information is
- required, <emphasis>you will need to check the documentation for your
- balancer</emphasis>. If your balancer provides <filename>.rdp</filename>
- files for convenience, look through the contents of those files for a string
- field called "loadbalanceinfo", as that field is where the required
- information/cookie would be specified.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>load-balance-info</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>loadbalanceinfo</primary>
- </indexterm>The load balancing information or cookie which
- should be provided to the connection broker. <emphasis>If no
- connection broker is being used, this should be left
- blank.</emphasis></para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-sftp">
- <title>RDP + SFTP</title>
- <para>Guacamole can provide file transfer over SFTP even when the remote desktop is
- otherwise being accessed through RDP and not SSH. If SFTP is enabled on a
- Guacamole RDP connection, users will be able to upload and download files as
- described in <xref linkend="using-guacamole"/>.</para>
- <para>This support is independent of the file transfer implemented through RDP's own
- "drive redirection" (RDPDR), and is particularly useful for RDP servers which do
- not support RDPDR.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>enable-sftp</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>file transfer</secondary>
- </indexterm><indexterm>
- <primary>SFTP</primary>
- </indexterm>Whether file transfer should be enabled. If set
- to "true", the user will be allowed to upload or download
- files from the specified server using SFTP. If omitted, SFTP
- will be disabled.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-hostname</parameter></entry>
- <entry>
- <para>The hostname or IP address of the server hosting SFTP.
- This parameter is optional. If omitted, the hostname of the
- RDP server specified with the
- <parameter>hostname</parameter> parameter will be
- used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-port</parameter></entry>
- <entry>
- <para>The port the SSH server providing SFTP is listening on,
- usually 22. This parameter is optional. If omitted, the
- standard port of 22 will be used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-host-key</parameter></entry>
- <entry>
- <para>The known hosts entry for the SFTP server. This
- parameter is optional, and, if not provided, no verification
- of SFTP host identity will be done. If the parameter is
- provided the identity of the server will be checked
- against the data.</para>
- <para>The format of this parameter is that of a single entry
- from an OpenSSH <filename>known_hosts</filename> file.</para>
- <para>For more information, please see <xref linkend="ssh-host-verification"/>.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-username</parameter></entry>
- <entry>
- <para>The username to authenticate as when connecting to the
- specified SSH server for SFTP. This parameter is optional if
- a username is specified for the RDP connection. If omitted,
- the value provided for the <parameter>username</parameter>
- parameter will be use.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-password</parameter></entry>
- <entry>
- <para>The password to use when authenticating with the specified
- SSH server for SFTP.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-private-key</parameter></entry>
- <entry>
- <para>The entire contents of the private key to use for public
- key authentication. If this parameter is not specified,
- public key authentication will not be used. The private key
- must be in OpenSSH format, as would be generated by the
- OpenSSH <command>ssh-keygen</command> utility.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-passphrase</parameter></entry>
- <entry>
- <para>The passphrase to use to decrypt the private key for use
- in public key authentication. This parameter is not needed
- if the private key does not require a passphrase.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-directory</parameter></entry>
- <entry>
- <para>The directory to upload files to if they are simply
- dragged and dropped, and thus otherwise lack a specific
- upload location. This parameter is optional. If omitted, the
- default upload location of the SSH server providing SFTP
- will be used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-root-directory</parameter></entry>
- <entry>
- <para>The directory to expose to connected users via Guacamole's
- <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="file-browser">file browser</link>. If omitted,
- the root directory will be used by default.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-server-alive-interval</parameter></entry>
- <entry>
- <para>The interval in seconds at which to send keepalive
- packets to the SSH server for the SFTP connection. This
- parameter is optional. If omitted, the default of 0 will be
- used, disabling sending keepalive packets. The minimum
- value is 2.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-disable-download</parameter></entry>
- <entry>
- <para>If set to true downloads from the remote system to
- the client (browser) will be disabled. The default is
- false, which means that downloads will be enabled.</para>
- <para>If sftp is not enabled, this parameter will be
- ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-disable-upload</parameter></entry>
- <entry>
- <para>If set to true uploads from the client (browser) to
- the remote system will be disabled. The default is
- false, which means that uploads will be enabled.</para>
- <para>If sftp is not enabled, this parameter will be
- ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-disable-clipboard">
- <title>Disabling clipboard access</title>
- <para>Guacamole provides bidirectional access to the clipboard by default for RDP
- connections. This behavior can be overridden on a per-connection basis with the
- <parameter>disable-copy</parameter> and <parameter>disable-paste</parameter>
- parameters.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>disable-copy</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>disable clipboard</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>disable clipboard</secondary>
- </indexterm>If set to "true", text copied within the RDP
- session will not be accessible by the user at the browser
- side of the Guacamole session, and will be usable only
- within the remote desktop. This parameter is optional. By
- default, the user will be given access to the copied
- text.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-paste</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>disable clipboard</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>disable clipboard</secondary>
- </indexterm>If set to "true", text copied at the browser
- side of the Guacamole session will not be accessible within
- the RDP session. This parameter is optional. By default, the
- user will be able to paste data from outside the browser
- within the RDP session.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-perf-flags">
- <title>Performance flags</title>
- <para>RDP provides several flags which control the availability of features that
- decrease performance and increase bandwidth for the sake of aesthetics, such as
- wallpaper, window theming, menu effects, and smooth fonts. These features are
- all disabled by default within Guacamole such that bandwidth usage is minimized,
- but you can manually re-enable them on a per-connection basis if desired.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="2.75*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>enable-wallpaper</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>wallpaper</secondary>
- </indexterm>If set to "true", enables rendering of the
- desktop wallpaper. By default, wallpaper will be disabled,
- such that unnecessary bandwidth need not be spent redrawing
- the desktop.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>enable-theming</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>theming</secondary>
- </indexterm>If set to "true", enables use of theming of
- windows and controls. By default, theming within RDP
- sessions is disabled.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>enable-font-smoothing</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>font smoothing</secondary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>ClearType</secondary>
- </indexterm>If set to "true", text will be rendered with
- smooth edges. Text over RDP is rendered with rough edges by
- default, as this reduces the number of colors used by text,
- and thus reduces the bandwidth required for the
- connection.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>enable-full-window-drag</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>full window drag</secondary>
- </indexterm>If set to "true", the contents of windows will
- be displayed as windows are moved. By default, the RDP
- server will only draw the window border while windows are
- being dragged.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>enable-desktop-composition</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>desktop composition</secondary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>Aero</secondary>
- </indexterm>If set to "true", graphical effects such as
- transparent windows and shadows will be allowed. By default,
- such effects, if available, are disabled.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>enable-menu-animations</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>menu animations</secondary>
- </indexterm>If set to "true", menu open and close animations
- will be allowed. Menu animations are disabled by
- default.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-bitmap-caching</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>bitmap caching</secondary>
- </indexterm>In certain situations, particularly with RDP server
- implementations with known bugs, it is necessary to disable
- RDP's built-in bitmap caching functionality. This parameter
- allows that to be controlled in a Guacamole session. If set to
- "true" the RDP bitmap cache will not be used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-offscreen-caching</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>offscreen bitmap caching</secondary>
- </indexterm>RDP normally maintains caches of regions of the screen
- that are current not visible in the client in order to accelerate
- retrieval of those regions when they come into view. This parameter,
- when set to "true," will disable caching of those regions. This is
- usually only useful when dealing with known bugs in RDP server
- implementations and should remain enabled in most circumstances.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-glyph-caching</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RDP</primary>
- <secondary>glyph caching</secondary>
- </indexterm>In addition to screen regions, RDP maintains caches of
- frequently used symbols or fonts, collectively known as "glyphs." As
- with bitmap and offscreen caching, certain known bugs in RDP implementations
- can cause performance issues with this enabled, and setting this parameter
- to "true" will disable that glyph caching in the RDP session.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-remoteapp">
- <title>RemoteApp</title>
- <para>Recent versions of Windows provide a feature called RemoteApp which allows
- individual applications to be used over RDP, without providing access to the
- full desktop environment. If your RDP server has this feature enabled and
- configured, you can configure Guacamole connections to use those individual
- applications.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>remote-app</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>RemoteApp</primary>
- </indexterm>Specifies the RemoteApp to start on the remote
- desktop. If supported by your remote desktop server, this
- application, and only this application, will be visible to
- the user.</para>
- <para>Windows requires a special notation for the names of
- remote applications. The names of remote applications must
- be prefixed with two vertical bars. For example, if you have
- created a remote application on your server for
- <filename>notepad.exe</filename> and have assigned it
- the name "notepad", you would set this parameter to:
- "||notepad".</para>
- </entry>
- </row>
- <row>
- <entry><parameter>remote-app-dir</parameter></entry>
- <entry>
- <para>The working directory, if any, for the remote application.
- This parameter has no effect if RemoteApp is not in
- use.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>remote-app-args</parameter></entry>
- <entry>
- <para>The command-line arguments, if any, for the remote
- application. This parameter has no effect if RemoteApp is
- not in use.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="rdp-wake-on-lan">
- <title>Wake-on-LAN Configuration</title>
- <para>Guacamole implements the support to send a "magic wake-on-lan
- packet" to a remote host prior to attempting to establish a
- connection with the host. The below parameters control the
- behavior of this functionality, which is disabled by default.
- </para>
- <important>
- <para>There are several factors that can impact the ability
- of Wake-on-LAN (WoL) to function correctly, many of which
- are outside the scope of Guacamole configuration. If you
- are configuring WoL within Guacamole you should also be
- familiar with the other components that need to be
- configured in order for it to function correctly.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>RDP</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>wol-send-packet</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-send-packet</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>wol-send-packet</secondary>
- </indexterm>If set to "true", Guacamole will
- attempt to send the Wake-On-LAN packet prior
- to establishing a connection. This parameter
- is optional. By default, Guacamole will
- not send the WoL packet. Enabling this
- option requires that the
- <parameter>wol-mac-addr</parameter>
- parameter also be configured, otherwise
- the WoL packet will not be sent.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-mac-addr</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-mac-addr</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>wol-mac-addr</secondary>
- </indexterm>This parameter configures the
- MAC address that Guacamole will use in
- the magic WoL packet to attempt to wake
- the remote system. If
- <parameter>wol-send-packet</parameter>
- is enabled, this parameter is required
- or else the WoL packet will not be sent.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-broadcast-addr</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-broadcast-addr</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>wol-broadcast-addr</secondary>
- </indexterm>This parameter configures the
- IPv4 broadcast address or IPv6 multicast
- address that Guacamole will send the
- WoL packet to in order to wake the host.
- This parameter is optional. If no value
- is provided, the default local IPv4 broadcast
- address (255.255.255.255) will be used.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-udp-port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-udp-port</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>wol-udp-port</secondary>
- </indexterm>This parameter configures the
- UDP port that will be set in the WoL packet.
- In most cases the UDP port isn't processed
- by the system that will be woken up; however,
- there are certain cases where it is useful
- for the port to be set, as in situations
- where a router is listening for the packet
- and can make routing decisions depending
- upon the port that is used. If not
- configured the default UDP port 9 will be
- used.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-wait-time</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-wait-time</primary>
- </indexterm><indexterm>
- <primary>RDP</primary>
- <secondary>wol-wait-time</secondary>
- </indexterm>By default after the WoL packet
- is sent Guacamole will attempt immediately
- to connect to the remote host. It may be
- desirable in certain scenarios to have
- Guacamole wait before the initial connection
- in order to give the remote system time to
- boot. Setting this parameter to a positive
- value will cause Guacamole to wait the specified
- number of seconds before attempting the initial
- connection. This parameter is optional.
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="adding-rdp">
- <title>Adding an RDP connection</title>
- <indexterm>
- <primary>RDP</primary>
- <secondary>adding</secondary>
- </indexterm>
- <para>If you are using the default authentication built into Guacamole, and you wish
- to grant access to a RDP connection to a particular user, you need to locate the
- <code><authorize></code> section for that user within your
- <filename>user-mapping.xml</filename>, and add a section like the following
- within it:</para>
- <programlisting><connection name="<replaceable>Unique Name</replaceable>">
- <protocol>rdp</protocol>
- <param name="hostname"><replaceable>localhost</replaceable></param>
- <param name="port"><replaceable>3389</replaceable></param>
-</connection></programlisting>
- <para>If added exactly as above, a new connection named "<replaceable>Unique
- Name</replaceable>" will be available to the user associated with the
- <code><authorize></code> section containing it. The connection will use
- RDP to connect to <replaceable>localhost</replaceable> at port
- <replaceable>3389</replaceable>. Naturally, you will want to change some or
- all of these values.</para>
- <para>If you want to login automatically rather than receive a login prompt upon
- connecting, you can specify a username and password with additional
- <code><param></code> tags. Other options are available for controlling
- the color depth, size of the screen, etc.</para>
- <para>Other authentication methods will provide documentation describing how to
- configure new connections. If the authentication method in use fully implements
- the features of Guacamole's authentication API, you will be able to add a new
- RDP connection easily and intuitively using the administration interface built
- into Guacamole. You will not need to edit configuration files.</para>
- </section>
- </section>
- <section xml:id="ssh">
- <title>SSH</title>
- <indexterm>
- <primary>SSH</primary>
- </indexterm>
- <para>Unlike VNC or RDP, SSH is a text protocol. Its implementation in Guacamole is
- actually a combination of a terminal emulator and SSH client, because the SSH
- protocol isn't inherently graphical. Guacamole's SSH support emulates a terminal on
- the server side, and draws the screen of this terminal remotely on the
- client.</para>
- <para>SSH support for Guacamole is provided by the <package>libguac-client-ssh</package>
- library, which will be installed as part of guacamole-server if the required
- dependencies are present during the build.</para>
- <section xml:id="ssh-host-verification">
- <title>SSH Host Verification</title>
- <para>By default, Guacamole does not do any verification of host identity before
- establishing SSH connections. While this may be safe for private and trusted
- networks, it is not ideal for large networks with unknown/untrusted systems,
- or for SSH connections that traverse the Internet. The potential exists for
- Man-in-the-Middle (MitM) attacks when connecting to these hosts.</para>
- <para>Guacamole includes two methods for verifying SSH (and SFTP) server identity
- that can be used to make sure that the host you are connecting to is a host
- that you know and trust. The first method is by reading a file in
- <varname>GUACAMOLE_HOME</varname> called <filename>ssh_known_hosts</filename>.
- This file should be in the format of a standard OpenSSH known_hosts file.
- If the file is not present, no verification is done. If the file is present,
- it is read in at connection time and remote host identities are verified
- against the keys present in the file.</para>
- <para>The second method for verifying host identity is by passing a connection
- parameter that contains an OpenSSH known hosts entry for that specific host.
- The <parameter>host-key</parameter> parameter is used for SSH connections,
- while the SFTP connections associated with RDP and VNC use the
- <parameter>sftp-host-key</parameter> parameter. If these parameters are
- not present on their respective connections no host identity verification
- is performed. If the parameter is present then the identity of the remote
- host is verified against the identity provided in the parameter before a
- connection is established.</para>
- </section>
- <section xml:id="ssh-network-parameters">
- <title>Network parameters</title>
- <para>SSH connections require a hostname or IP address defining the destination
- machine. SSH is standardized to use port 22 and this will be the proper value in
- most cases. You only need to specify the SSH port if you are not using the
- standard port.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>hostname</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>hostname</secondary>
- </indexterm>The hostname or IP address of the SSH server
- Guacamole should connect to.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>port</secondary>
- </indexterm>The port the SSH server is listening on, usually
- 22. This parameter is optional. If this is not specified,
- the default of 22 will be used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>host-key</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>host-key</secondary>
- </indexterm>The known hosts entry for the SSH server. This
- parameter is optional, and, if not provided, no verification
- of host identity will be done. If the parameter is
- provided the identity of the server will be checked
- against the data.</para>
- <para>The format of this parameter is that of a single entry from
- an OpenSSH <filename>known_hosts</filename> file.</para>
- <para>For more information, please see <xref linkend="ssh-host-verification"/>.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>server-alive-interval</parameter></entry>
- <entry>
- <para>
- <indexterm>
- <primary>SSH</primary>
- <secondary>server-alive-interval</secondary>
- </indexterm>
- By default the SSH client does not send keepalive requests
- to the server. This parameter allows you to configure the
- the interval in seconds at which the client connection
- sends keepalive packets to the server. The default is 0,
- which disables sending the packets. The minimum value
- is 2.
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="ssh-authentication">
- <title>Authentication</title>
- <para>SSH provides authentication through passwords and public key
- authentication, and also supports the NONE method.</para>
- <para>SSH NONE authentication is seen occasionally in appliances
- and items like network or SAN fabric switches. Generally
- for this authentication method you need only provide a
- username.</para>
- <para>For Guacamole to use public key authentication, it must have access to your
- private key and, if applicable, its passphrase. If the private key requires a
- passphrase, but no passphrase is provided, you will be prompted for the
- passphrase upon connecting.</para>
- <para>If no private key is provided, Guacamole will attempt to authenticate using a
- password, reading that password from the connection parameters, if provided, or
- by prompting the user directly.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>username</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>username</secondary>
- </indexterm>The username to use to authenticate, if any.
- This parameter is optional. If not specified, you will be
- prompted for the username upon connecting.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>password</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>password</secondary>
- </indexterm>The password to use when attempting
- authentication, if any. This parameter is optional. If not
- specified, you will be prompted for your password upon
- connecting.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>private-key</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>public key authentication</secondary>
- </indexterm>The entire contents of the private key to use
- for public key authentication. If this parameter is not
- specified, public key authentication will not be used. The
- private key must be in OpenSSH format, as would be generated
- by the OpenSSH <command>ssh-keygen</command> utility.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>passphrase</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>passphrase</secondary>
- </indexterm>The passphrase to use to decrypt the private key
- for use in public key authentication. This parameter is not
- needed if the private key does not require a passphrase. If
- the private key requires a passphrase, but this parameter is
- not provided, the user will be prompted for the passphrase
- upon connecting.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="ssh-display-settings">
- <title>Display settings</title>
- <para>Guacamole's SSH support provides a display, but not in the same sense as a
- remote desktop protocol like VNC or RDP. The display is a terminal emulator, and
- thus provides options for configuring the font used and its size. In this case,
- <emphasis>the chosen font must be installed on the server</emphasis>, as it
- is the server that will handle rendering of characters to the terminal display,
- not the client.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>color-scheme</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>color scheme</secondary>
- </indexterm>The color scheme to use for the terminal
- emulator used by SSH connections. It consists of a
- semicolon-separated series of name-value pairs. Each
- name-value pair is separated by a colon and assigns a
- value to a color in the terminal emulator palette. For
- example, to use blue text on white background by default,
- and change the red color to a purple shade, you would
- specify:</para>
- <informalexample>
- <programlisting>foreground: rgb:00/00/ff;
-background: rgb:ff/ff/ff;
-color9: rgb:80/00/80</programlisting>
- </informalexample>
- <para>This format is similar to the color configuration format
- used by Xterm, so Xterm color configurations can be easily
- adapted for Guacamole. This parameter is optional. If not
- specified, Guacamole will render text as gray over a black
- background.</para>
- <para>Possible color names are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>foreground</constant></term>
- <listitem>
- <para>Set the default foreground color.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>background</constant></term>
- <listitem>
- <para>Set the default background color.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>color<n></constant></term>
- <listitem>
- <para>Set the color at index <code><n></code>
- on the Xterm 256-color palette. For example,
- <code>color9</code> refers to the red color.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Possible color values are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>rgb:RR/GG/BB</constant></term>
- <listitem>
- <para>Use the specified color in RGB format, with
- each component in hexadecimal. For example,
- <code>rgb:ff/00/00</code> specifies the color
- red. Note that each hexadecimal component can be
- one to four digits, but the effective values are
- always zero-extended or truncated to two digits;
- for example, <code>rgb:f/8/0</code>,
- <code>rgb:f0/80/00</code>, and
- <code>rgb:f0f/808/00f</code> all refer to the
- same effective color.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>color<n></constant></term>
- <listitem>
- <para>Use the color currently assigned to index
- <code><n></code> on the Xterm 256-color
- palette. For example, <code>color9</code>
- specifies the current red color. Note that the
- color value is used rather than the color
- reference, so if <code>color9</code> is changed
- later in the color scheme configuration, that
- new color will not be reflected in this
- assignment.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>For backward compatibility, Guacamole will also accept
- four special values as the color scheme parameter:</para>
- <variablelist>
- <varlistentry>
- <term><constant>black-white</constant></term>
- <listitem>
- <para>Black text over a white background.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>gray-black</constant></term>
- <listitem>
- <para>Gray text over a black background. This is the
- default color scheme.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>green-black</constant></term>
- <listitem>
- <para>Green text over a black background.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>white-black</constant></term>
- <listitem>
- <para>White text over a black background.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </entry>
- </row>
- <row>
- <entry><parameter>font-name</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>font</secondary>
- </indexterm>The name of the font to use. This parameter is
- optional. If not specified, the default of "monospace" will
- be used instead.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>font-size</parameter></entry>
- <entry>
- <para>The size of the font to use, in points. This parameter is
- optional. If not specified, the default of 12 will be used
- instead.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>scrollback</parameter></entry>
- <entry>
- <para>The maximum number of rows to allow within the terminal
- scrollback buffer. This parameter is optional. If not
- specified, the scrollback buffer will be limited to a
- maximum of 1000 rows.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="ssh-command">
- <title>Running a command (instead of a shell)</title>
- <para>By default, SSH sessions will start an interactive shell. The shell which will
- be used is determined by the SSH server, normally by reading the user's default
- shell previously set with <command>chsh</command> or within
- <filename>/etc/passwd</filename>. If you wish to override this and instead
- run a specific command, you can do so by specifying that command in the
- configuration of the Guacamole SSH connection.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>command</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>command</secondary>
- </indexterm>The command to execute over the SSH session, if
- any. This parameter is optional. If not specified, the SSH
- session will use the user's default shell.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section>
- <title>Internationalization/Locale settings</title>
- <para>The language of the session is normally set by the SSH server. If the SSH
- server allows the relevant environment variable to be set, the language can be
- overridden on a per-connection basis.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>locale</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>locale</secondary>
- </indexterm>The specific locale to request for the SSH
- session. This parameter is optional and may be any value
- accepted by the <envar>LANG</envar> environment variable of
- the SSH server. If not specified, the SSH server's default
- locale will be used.</para>
- <para>As this parameter is sent to the SSH server using the
- <envar>LANG</envar> environment variable, the parameter
- will only have an effect if the SSH server allows the
- <envar>LANG</envar> environment variable to be set by
- SSH clients.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>timezone</parameter></entry>
- <entry>
- <para>
- <indexterm>
- <primary>SSH</primary>
- <secondary>timezone</secondary>
- </indexterm>This parameter allows you
- to control the timezone that is sent
- to the server over the SSH connection,
- which will change the way local time is
- displayed on the server.</para>
- <para>
- The mechanism used to do this over SSH
- connections is by setting the
- <envar>TZ</envar> variable on the SSH
- connection to the timezone specified by
- this parameter. This means that the SSH
- server must allow the <envar>TZ</envar>
- variable to be set/overriden - many SSH
- server implementations have this disabled
- by default. To get this to work, you may
- need to modify the configuration of the
- SSH server and explicitly allow for
- <envar>TZ</envar> to be set/overriden.
- </para>
- <para>
- The available values of this parameter are
- standard IANA key zone format timezones,
- and the value will be sent directly to
- the server in this format.
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="ssh-terminal-behavior">
- <title>Controlling terminal behavior</title>
- <para>In most cases, the default behavior for a terminal works without modification.
- However, when connecting to certain systems, particularly operating systems other
- than Linux, the terminal behavior may need to be tweaked to allow it to operate
- properly. The settings in this section control that behavior.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>backspace</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>backspace</secondary>
- </indexterm>This parameter controls the ASCII code that
- the backspace key sends to the remote system. Under most
- circumstances this should not need to be adjusted; however,
- if, when pressing the backspace key, you see control characters
- (often either ^? or ^H) instead of seeing the text erased,
- you may need to adjust this parameter. By default the terminal
- sends ASCII code 127 (Delete) if this option is not set.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>terminal-type</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>terminal type</secondary>
- </indexterm>This parameter sets the terminal emulator type
- string that is passed to the SSH server. This parameter is
- optional. If not specified, "<code>linux</code>"
- is used as the terminal emulator type by default.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <section xml:id="ssh-stdin-pipe">
- <title>Providing input directly from JavaScript</title>
- <para>If Guacamole is being used in part to automate an SSH session, it can be
- useful to provide input directly from JavaScript as a raw stream of data,
- rather than attempting to translate data into keystrokes. This can be done
- through opening a pipe stream named "STDIN" within the SSH connection using
- the <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="../guacamole-common-js/Guacamole.Client.html#createPipeStream"
- ><function>createPipeStream()</function></link> function of <link
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="../guacamole-common-js/Guacamole.Client.html"
- ><classname>Guacamole.Client</classname></link>:</para>
- <informalexample>
- <programlisting>var outputStream = client.createPipeStream('text/plain', 'STDIN');</programlisting>
- </informalexample>
- <para>The resulting <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="../guacamole-common-js/Guacamole.OutputStream.html"
- ><classname>Guacamole.OutputStream</classname></link> can then be
- used to stream data directly to the input of the SSH session, as if typed by
- the user:</para>
- <informalexample>
- <programlisting>// Wrap output stream in writer
-var writer = new Guacamole.StringWriter(outputStream);
-
-// Send text
-writer.sendText("hello");
-
-// Send more text
-writer.sendText("world");
-
-// Close writer and stream
-writer.sendEnd();</programlisting>
- </informalexample>
- </section>
- </section>
- <section xml:id="ssh-typescripts">
- <title>Text session recording (typescripts)</title>
- <para>The full, raw text content of SSH sessions, including timing information, can
- be recorded automatically to a specified directory. This recording, also known
- as a "typescript", will be written to two files within the directory specified
- by <parameter>typescript-path</parameter>:
- <filename><replaceable>NAME</replaceable></filename>, which contains the
- raw text data, and <filename><replaceable>NAME</replaceable>.timing</filename>,
- which contains timing information, where <replaceable>NAME</replaceable> is the
- value provided for the <parameter>typescript-name</parameter> parameter.</para>
- <para>This format is compatible with the format used by the standard UNIX
- <command>script</command> command, and can be replayed using
- <command>scriptreplay</command> (if installed). For example, to replay a
- typescript called "<replaceable>NAME</replaceable>", you would run:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>scriptreplay <replaceable>NAME</replaceable>.timing <replaceable>NAME</replaceable></userinput></screen>
- </informalexample>
- <important>
- <para>Guacamole will never overwrite an existing recording. If necessary, a
- numeric suffix like ".1", ".2", ".3", etc. will be appended to
- <replaceable>NAME</replaceable> to avoid overwriting an existing
- recording. If even appending a numeric suffix does not help, the session
- will simply not be recorded.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>typescript-path</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>typescripts</secondary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary>text recording</secondary>
- </indexterm>The directory in which typescript files should
- be created. <emphasis>If a typescript needs to be recorded,
- this parameter is required.</emphasis> Specifying this
- parameter enables typescript recording. If this parameter is
- omitted, no typescript will be recorded.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>create-typescript-path</parameter></entry>
- <entry>
- <para>If set to "true", the directory specified by the
- <parameter>typescript-path</parameter> parameter will
- automatically be created if it does not yet exist. Only the
- final directory in the path will be created - if other
- directories earlier in the path do not exist, automatic
- creation will fail, and an error will be logged.</para>
- <para><emphasis>This parameter is optional.</emphasis> By
- default, the directory specified by the
- <parameter>typescript-path</parameter> parameter will
- not automatically be created, and attempts to record
- typescripts in a non-existent directory will be logged as
- errors.</para>
- <para>This parameter only has an effect if typescript recording
- is enabled. If the <parameter>typescript-path</parameter> is
- not specified, recording of typescripts will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>typescript-name</parameter></entry>
- <entry>
- <para>The base filename to use when determining the names for
- the data and timing files of the typescript. <emphasis>This
- parameter is optional.</emphasis> If omitted, the value
- "typescript" will be used instead.</para>
- <para>Each typescript consists of two files which are created
- within the directory specified by
- <parameter>typescript-path</parameter>:
- <filename><replaceable>NAME</replaceable></filename>,
- which contains the raw text data, and
- <filename><replaceable>NAME</replaceable>.timing</filename>,
- which contains timing information, where
- <replaceable>NAME</replaceable> is the value provided
- for the <parameter>typescript-name</parameter>
- parameter.</para>
- <para>This parameter only has an effect if typescript recording
- is enabled. If the <parameter>typescript-path</parameter> is
- not specified, recording of typescripts will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="ssh-recording">
- <title>Graphical session recording</title>
- <para>In addition to text-based recordings, SSH sessions can be recorded
- graphically. These recordings take the form of Guacamole protocol dumps and are
- recorded automatically to a specified directory. Recordings can be subsequently
- translated to a normal video stream using the <command>guacenc</command> utility
- provided with guacamole-server.</para>
- <para>For example, to produce a video called "<replaceable>NAME</replaceable>.m4v"
- from the recording "<replaceable>NAME</replaceable>", you would run:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guacenc <replaceable>/path/to/recording/NAME</replaceable></userinput></screen>
- </informalexample>
- <para>The <command>guacenc</command> utility has additional options for overriding
- default behavior, including tweaking the output format, which are documented in
- detail within the manpage:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>man guacenc</userinput></screen>
- </informalexample>
- <para>If recording of key events is explicitly enabled using the
- <parameter>recording-include-keys</parameter> parameter, recordings can also
- be translated into human-readable interpretations of the keys pressed during the
- session using the <command>guaclog</command> utility. The usage of
- <command>guaclog</command> is analogous to <command>guacenc</command>, and
- results in the creation of a new text file containing the interpreted
- events:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guaclog <replaceable>/path/to/recording/NAME</replaceable></userinput><computeroutput>
-guaclog: INFO: Guacamole input log interpreter (guaclog) version 1.3.0
-guaclog: INFO: 1 input file(s) provided.
-guaclog: INFO: Writing input events from "<replaceable>/path/to/recording/NAME</replaceable>" to "<replaceable annotations="">/path/to/recording/NAME</replaceable>.txt" ...
-guaclog: INFO: All files interpreted successfully.</computeroutput>
-<prompt>$</prompt> </screen>
- </informalexample>
- <important>
- <para>Guacamole will never overwrite an existing recording. If necessary, a
- numeric suffix like ".1", ".2", ".3", etc. will be appended to
- <replaceable>NAME</replaceable> to avoid overwriting an existing
- recording. If even appending a numeric suffix does not help, the session
- will simply not be recorded.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>recording-path</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>graphical recording</secondary>
- </indexterm>The directory in which screen recording files
- should be created. <emphasis>If a graphical recording needs
- to be created, then this parameter is
- required.</emphasis> Specifying this parameter enables
- graphical screen recording. If this parameter is omitted, no
- graphical recording will be created.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>create-recording-path</parameter></entry>
- <entry>
- <para>If set to "true", the directory specified by the
- <parameter>recording-path</parameter> parameter will
- automatically be created if it does not yet exist. Only the
- final directory in the path will be created - if other
- directories earlier in the path do not exist, automatic
- creation will fail, and an error will be logged.</para>
- <para><emphasis>This parameter is optional.</emphasis> By
- default, the directory specified by the
- <parameter>recording-path</parameter> parameter will not
- automatically be created, and attempts to create recordings
- within a non-existent directory will be logged as
- errors.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-name</parameter></entry>
- <entry>
- <para>The filename to use for any created recordings.
- <emphasis>This parameter is optional.</emphasis> If
- omitted, the value "recording" will be used instead.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-output</parameter></entry>
- <entry>
- <para>If set to "true", graphical output and other data normally
- streamed from server to client will be excluded from the
- recording, producing a recording which contains only user
- input events. <emphasis>This parameter is
- optional.</emphasis> If omitted, graphical output will
- be included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-mouse</parameter></entry>
- <entry>
- <para>If set to "true", user mouse events will be excluded from
- the recording, producing a recording which lacks a visible
- mouse cursor. <emphasis>This parameter is
- optional.</emphasis> If omitted, mouse events will be
- included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-include-keys</parameter></entry>
- <entry>
- <para>If set to "true", user key events will be included in the
- recording. The recording can subsequently be passed through
- the <command>guaclog</command> utility to produce a
- human-readable interpretation of the keys pressed during the
- session. <emphasis>This parameter is optional.</emphasis> If
- omitted, key events will be not included in the
- recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="ssh-sftp">
- <title>SFTP</title>
- <para>Guacamole provides support for file transfer over SSH using SFTP, the file
- transfer protocol built into most SSH servers. If SFTP is enabled on a Guacamole
- SSH connection, users will be able to upload and download files as described in
- <xref linkend="using-guacamole"/>.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>enable-sftp</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>SSH</primary>
- <secondary>file transfer</secondary>
- </indexterm><indexterm>
- <primary>SFTP</primary>
- </indexterm>Whether file transfer should be enabled. If set
- to "true", the user will be allowed to upload or download
- files from the SSH server using SFTP. Guacamole includes the
- <command>guacctl</command> utility which controls file
- downloads and uploads when run on the SSH server by the user
- over the SSH connection.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-root-directory</parameter></entry>
- <entry>
- <para>The directory to expose to connected users via Guacamole's
- <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="file-browser">file browser</link>. If omitted,
- the root directory will be used by default.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-disable-download</parameter></entry>
- <entry>
- <para>If set to true downloads from the remote system to
- the client (browser) will be disabled. The default is
- false, which means that downloads will be enabled.</para>
- <para>If sftp is not enabled, this parameter will be
- ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>sftp-disable-upload</parameter></entry>
- <entry>
- <para>If set to true uploads from the client (browser) to
- the remote system will be disabled. The default is
- false, which means that uploads will be enabled.</para>
- <para>If sftp is not enabled, this parameter will be
- ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="ssh-disable-clipboard">
- <title>Disabling clipboard access</title>
- <para>Guacamole provides bidirectional access to the terminal clipboard by default
- for SSH connections. This behavior can be overridden on a per-connection basis
- with the <parameter>disable-copy</parameter> and
- <parameter>disable-paste</parameter> parameters.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>disable-copy</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>disable clipboard</primary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary>disable clipboard</secondary>
- </indexterm>If set to "true", text copied within the SSH
- session will not be accessible by the user at the browser
- side of the Guacamole session, and will be usable only
- within the terminal. This parameter is optional. By default,
- the user will be given access to the copied text.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-paste</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>disable clipboard</primary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary>disable clipboard</secondary>
- </indexterm>If set to "true", text copied at the browser
- side of the Guacamole session will not be accessible within
- the SSH session. This parameter is optional. By default, the
- user will be able to paste data from outside the browser
- within the terminal.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="ssh-wake-on-lan">
- <title>Wake-on-LAN Configuration</title>
- <para>Guacamole implements the support to send a "magic wake-on-lan
- packet" to a remote host prior to attempting to establish a
- connection with the host. The below parameters control the
- behavior of this functionality, which is disabled by default.
- </para>
- <important>
- <para>There are several factors that can impact the ability
- of Wake-on-LAN (WoL) to function correctly, many of which
- are outside the scope of Guacamole configuration. If you
- are configuring WoL within Guacamole you should also be
- familiar with the other components that need to be
- configured in order for it to function correctly.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>SSH</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>wol-send-packet</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-send-packet</primary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary>wol-send-packet</secondary>
- </indexterm>If set to "true", Guacamole will
- attempt to send the Wake-On-LAN packet prior
- to establishing a connection. This parameter
- is optional. By default, Guacamole will
- not send the WoL packet. Enabling this
- option requires that the
- <parameter>wol-mac-addr</parameter>
- parameter also be configured, otherwise
- the WoL packet will not be sent.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-mac-addr</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-mac-addr</primary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary>wol-mac-addr</secondary>
- </indexterm>This parameter configures the
- MAC address that Guacamole will use in
- the magic WoL packet to attempt to wake
- the remote system. If
- <parameter>wol-send-packet</parameter>
- is enabled, this parameter is required
- or else the WoL packet will not be sent.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-broadcast-addr</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-broadcast-addr</primary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary>wol-broadcast-addr</secondary>
- </indexterm>This parameter configures the
- IPv4 broadcast address or IPv6 multicast
- address that Guacamole will send the
- WoL packet to in order to wake the host.
- This parameter is optional. If no value
- is provided, the default local IPv4 broadcast
- address (255.255.255.255) will be used.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-udp-port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-udp-port</primary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary>wol-udp-port</secondary>
- </indexterm>This parameter configures the
- UDP port that will be set in the WoL packet.
- In most cases the UDP port isn't processed
- by the system that will be woken up; however,
- there are certain cases where it is useful
- for the port to be set, as in situations
- where a router is listening for the packet
- and can make routing decisions depending
- upon the port that is used. If not
- configured the default UDP port 9 will be
- used.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-wait-time</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-wait-time</primary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary>wol-wait-time</secondary>
- </indexterm>By default after the WoL packet
- is sent Guacamole will attempt immediately
- to connect to the remote host. It may be
- desirable in certain scenarios to have
- Guacamole wait before the initial connection
- in order to give the remote system time to
- boot. Setting this parameter to a positive
- value will cause Guacamole to wait the specified
- number of seconds before attempting the initial
- connection. This parameter is optional.
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="adding-ssh">
- <title>Adding an SSH connection</title>
- <indexterm>
- <primary>SSH</primary>
- <secondary>adding</secondary>
- </indexterm>
- <para>If you are using the default authentication built into Guacamole, and you wish
- to grant access to a SSH connection to a particular user, you need to locate the
- <code><authorize></code> section for that user within your
- <filename>user-mapping.xml</filename>, and add a section like the following
- within it:</para>
- <programlisting><connection name="<replaceable>Unique Name</replaceable>">
- <protocol>ssh</protocol>
- <param name="hostname"><replaceable>localhost</replaceable></param>
- <param name="port"><replaceable>22</replaceable></param>
-</connection></programlisting>
- <para>If added exactly as above, a new connection named "<replaceable>Unique
- Name</replaceable>" will be available to the user associated with the
- <code><authorize></code> section containing it. The connection will use
- SSH to connect to <replaceable>localhost</replaceable> at port
- <replaceable>22</replaceable>. Naturally, you will want to change some or
- all of these values.</para>
- <para>If you want to login automatically rather than receive a login prompt upon
- connecting, you can specify a username and password with additional
- <code><param></code> tags. Other options are available for controlling
- the font.</para>
- <para>Other authentication methods will provide documentation describing how to
- configure new connections.</para>
- </section>
- </section>
- <section xml:id="telnet">
- <title>Telnet</title>
- <indexterm>
- <primary>telnet</primary>
- </indexterm>
- <para>Telnet is a text protocol and provides similar functionality to SSH. By nature, it
- is not encrypted, and does not provide support for file transfer. As far as graphics
- are concerned, Guacamole's telnet support works in the same manner as SSH: it
- emulates a terminal on the server side which renders to the Guacamole client's
- display.</para>
- <para>Telnet support for Guacamole is provided by the
- <package>libguac-client-telnet</package> library, which will be installed as
- part of guacamole-server if the required dependencies are present during the
- build.</para>
- <section xml:id="telnet-network-parameters">
- <title>Network parameters</title>
- <para>Telnet connections require a hostname or IP address defining the destination
- machine. Telnet is standardized to use port 23 and this will be the proper value
- in most cases. You only need to specify the telnet port if you are not using the
- standard port.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>telnet</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>hostname</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>hostname</secondary>
- </indexterm>The hostname or IP address of the telnet server
- Guacamole should connect to.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>port</secondary>
- </indexterm>The port the telnet server is listening on,
- usually 23. This parameter is optional. If this is not
- specified, the default of 23 will be used.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="telnet-authentication">
- <title>Authentication</title>
- <para>Telnet does not actually provide any standard means of authentication.
- Authentication over telnet depends entirely on the login process running on the
- server and is interactive. To cope with this, Guacamole provides non-standard
- mechanisms for automatically passing the username and entering password. Whether
- these mechanisms work depends on specific login process used by your telnet
- server.</para>
- <para>The de-facto method for passing the username automatically via telnet is to
- submit it via the <envar>USER</envar> environment variable, sent using the
- <methodname>NEW-ENVIRON</methodname> option. This is the mechanism used by
- most telnet clients, typically via the <option>-l</option> command-line
- option.</para>
- <para>Passwords cannot typically be sent automatically - at least not as reliably as
- the username. There is no <envar>PASSWORD</envar> environment variable (this
- would actually be a horrible idea) nor any similar mechanism for passing the
- password to the telnet login process, and most telnet clients provide no
- built-in support for automatically entering the password. The best that can be
- done is to heuristically detect the password prompt, and type the password on
- behalf of the user when the prompt appears. The prescribed method for doing this
- with a traditional command-line telnet is to use a utility like
- <command>expect</command>. Guacamole provides similar functionality by
- searching for the password prompt with a regular expression.</para>
- <para>If Guacamole receives a line of text which matches the regular expression, the
- password is automatically sent. If no such line is ever received, the password
- is not sent, and the user must type the password manually. Pressing any key
- during this process cancels the heuristic password prompt detection.</para>
- <para>If the password prompt is not being detected properly, you can try using your
- own regular expression by specifying it within the
- <parameter>password-regex</parameter> parameter. The regular expression must
- be written in the POSIX ERE dialect (the dialect typically used by
- <command>egrep</command>).</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>telnet</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>username</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>username</secondary>
- </indexterm>The username to use to authenticate, if any.
- This parameter is optional. If not specified, or not
- supported by the telnet server, the login process on the
- telnet server will prompt you for your credentials. For this
- to work, your telnet server must support the
- <methodname>NEW-ENVIRON</methodname> option, and the
- telnet login process must pay attention to the
- <envar>USER</envar> environment variable. Most telnet
- servers satisfy this criteria.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>password</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>password</secondary>
- </indexterm>The password to use when attempting
- authentication, if any. This parameter is optional. If
- specified, your password will be typed on your behalf when
- the password prompt is detected.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>username-regex</parameter></entry>
- <entry>
- <para>The regular expression to use when waiting for the
- username prompt. This parameter is optional. If not
- specified, a reasonable default built into Guacamole will be
- used. The regular expression must be written in the POSIX
- ERE dialect (the dialect typically used by
- <command>egrep</command>).</para>
- </entry>
- </row>
- <row>
- <entry><parameter>password-regex</parameter></entry>
- <entry>
- <para>The regular expression to use when waiting for the
- password prompt. This parameter is optional. If not
- specified, a reasonable default built into Guacamole will be
- used. The regular expression must be written in the POSIX
- ERE dialect (the dialect typically used by
- <command>egrep</command>).</para>
- </entry>
- </row>
- <row>
- <entry><parameter>login-success-regex</parameter></entry>
- <entry>
- <para>The regular expression to use when detecting that the
- login attempt has succeeded. This parameter is optional. If
- specified, the terminal display will not be shown to the
- user until text matching this regular expression has been
- received from the telnet server. The regular expression must
- be written in the POSIX ERE dialect (the dialect typically
- used by <command>egrep</command>).</para>
- </entry>
- </row>
- <row>
- <entry><parameter>login-failure-regex</parameter></entry>
- <entry>
- <para>The regular expression to use when detecting that the
- login attempt has failed. This parameter is optional. If
- specified, the connection will be closed with an explicit
- login failure error if text matching this regular expression
- has been received from the telnet server. The regular
- expression must be written in the POSIX ERE dialect (the
- dialect typically used by <command>egrep</command>).</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="telnet-display-settings">
- <title>Display settings</title>
- <para>Guacamole's telnet support provides a display, but not in the same sense as a
- remote desktop protocol like VNC or RDP. The display is a terminal emulator, and
- thus provides options for configuring the font used and its size. In this case,
- <emphasis>the chosen font must be installed on the server</emphasis>, as it
- is the server that will handle rendering of characters to the terminal display,
- not the client.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>telnet</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>color-scheme</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>color scheme</secondary>
- </indexterm>The color scheme to use for the terminal
- emulator used by telnet connections. It consists of a
- semicolon-separated series of name-value pairs. Each
- name-value pair is separated by a colon and assigns a
- value to a color in the terminal emulator palette. For
- example, to use blue text on white background by default,
- and change the red color to a purple shade, you would
- specify:</para>
- <informalexample>
- <programlisting>foreground: rgb:00/00/ff;
-background: rgb:ff/ff/ff;
-color9: rgb:80/00/80</programlisting>
- </informalexample>
- <para>This format is similar to the color configuration format
- used by Xterm, so Xterm color configurations can be easily
- adapted for Guacamole. This parameter is optional. If not
- specified, Guacamole will render text as gray over a black
- background.</para>
- <para>Possible color names are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>foreground</constant></term>
- <listitem>
- <para>Set the default foreground color.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>background</constant></term>
- <listitem>
- <para>Set the default background color.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>color<n></constant></term>
- <listitem>
- <para>Set the color at index <code><n></code>
- on the Xterm 256-color palette. For example,
- <code>color9</code> refers to the red color.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Possible color values are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>rgb:RR/GG/BB</constant></term>
- <listitem>
- <para>Use the specified color in RGB format, with
- each component in hexadecimal. For example,
- <code>rgb:ff/00/00</code> specifies the color
- red. Note that each hexadecimal component can be
- one to four digits, but the effective values are
- always zero-extended or truncated to two digits;
- for example, <code>rgb:f/8/0</code>,
- <code>rgb:f0/80/00</code>, and
- <code>rgb:f0f/808/00f</code> all refer to the
- same effective color.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>color<n></constant></term>
- <listitem>
- <para>Use the color currently assigned to index
- <code><n></code> on the Xterm 256-color
- palette. For example, <code>color9</code>
- specifies the current red color. Note that the
- color value is used rather than the color
- reference, so if <code>color9</code> is changed
- later in the color scheme configuration, that
- new color will not be reflected in this
- assignment.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>For backward compatibility, Guacamole will also accept
- four special values as the color scheme parameter:</para>
- <variablelist>
- <varlistentry>
- <term><constant>black-white</constant></term>
- <listitem>
- <para>Black text over a white background.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>gray-black</constant></term>
- <listitem>
- <para>Gray text over a black background. This is the
- default color scheme.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>green-black</constant></term>
- <listitem>
- <para>Green text over a black background.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>white-black</constant></term>
- <listitem>
- <para>White text over a black background.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </entry>
- </row>
- <row>
- <entry><parameter>font-name</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>font</secondary>
- </indexterm>The name of the font to use. This parameter is
- optional. If not specified, the default of "monospace" will
- be used instead.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>font-size</parameter></entry>
- <entry>
- <para>The size of the font to use, in points. This parameter is
- optional. If not specified, the default of 12 will be used
- instead.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>scrollback</parameter></entry>
- <entry>
- <para>The maximum number of rows to allow within the terminal
- scrollback buffer. This parameter is optional. If not
- specified, the scrollback buffer will be limited to a
- maximum of 1000 rows.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="telnet-terminal-behavior">
- <title>Controlling terminal behavior</title>
- <para>In most cases, the default behavior for a terminal works without modification.
- However, when connecting to certain systems, particularly operating systems other
- than Linux, the terminal behavior may need to be tweaked to allow it to operate
- properly. The settings in this section control that behavior.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>telnet</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>backspace</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>backspace</secondary>
- </indexterm>This parameter controls the ASCII code that
- the backspace key sends to the remote system. Under most
- circumstances this should not need to be adjusted; however,
- if, when pressing the backspace key, you see control characters
- (often either ^? or ^H) instead of seeing the text erased,
- you may need to adjust this parameter. By default the terminal
- sends ASCII code 127 (Delete) if this option is not set.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>terminal-type</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>terminal type</secondary>
- </indexterm>This parameter sets the terminal emulator type
- string that is passed to the telnet server. This parameter
- is optional. If not specified,
- "<code>linux</code>" is used as the terminal
- emulator type by default.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <section xml:id="telnet-stdin-pipe">
- <title>Providing input directly from JavaScript</title>
- <para>If Guacamole is being used in part to automate a telnet session, it can be
- useful to provide input directly from JavaScript as a raw stream of data,
- rather than attempting to translate data into keystrokes. This can be done
- through opening a pipe stream named "STDIN" within the telnet connection
- using the <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="../guacamole-common-js/Guacamole.Client.html#createPipeStream"
- ><function>createPipeStream()</function></link> function of <link
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="../guacamole-common-js/Guacamole.Client.html"
- ><classname>Guacamole.Client</classname></link>:</para>
- <informalexample>
- <programlisting>var outputStream = client.createPipeStream('text/plain', 'STDIN');</programlisting>
- </informalexample>
- <para>The resulting <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="../guacamole-common-js/Guacamole.OutputStream.html"
- ><classname>Guacamole.OutputStream</classname></link> can then be
- used to stream data directly to the input of the telnet session, as if typed
- by the user:</para>
- <informalexample>
- <programlisting>// Wrap output stream in writer
-var writer = new Guacamole.StringWriter(outputStream);
-
-// Send text
-writer.sendText("hello");
-
-// Send more text
-writer.sendText("world");
-
-// Close writer and stream
-writer.sendEnd();</programlisting>
- </informalexample>
- </section>
- </section>
- <section xml:id="telnet-typescripts">
- <title>Text session recording (typescripts)</title>
- <para>The full, raw text content of telnet sessions, including timing information,
- can be recorded automatically to a specified directory. This recording, also
- known as a "typescript", will be written to two files within the directory
- specified by <parameter>typescript-path</parameter>:
- <filename><replaceable>NAME</replaceable></filename>, which contains the
- raw text data, and <filename><replaceable>NAME</replaceable>.timing</filename>,
- which contains timing information, where <replaceable>NAME</replaceable> is the
- value provided for the <parameter>typescript-name</parameter> parameter.</para>
- <para>This format is compatible with the format used by the standard UNIX
- <command>script</command> command, and can be replayed using
- <command>scriptreplay</command> (if installed). For example, to replay a
- typescript called "<replaceable>NAME</replaceable>", you would run:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>scriptreplay <replaceable>NAME</replaceable>.timing <replaceable>NAME</replaceable></userinput></screen>
- </informalexample>
- <important>
- <para>Guacamole will never overwrite an existing recording. If necessary, a
- numeric suffix like ".1", ".2", ".3", etc. will be appended to
- <replaceable>NAME</replaceable> to avoid overwriting an existing
- recording. If even appending a numeric suffix does not help, the session
- will simply not be recorded.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>telnet</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>typescript-path</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>typescripts</secondary>
- </indexterm><indexterm>
- <primary>telnet</primary>
- <secondary>text recording</secondary>
- </indexterm>The directory in which typescript files should
- be created. <emphasis>If a typescript needs to be recorded,
- this parameter is required.</emphasis> Specifying this
- parameter enables typescript recording. If this parameter is
- omitted, no typescript will be recorded.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>create-typescript-path</parameter></entry>
- <entry>
- <para>If set to "true", the directory specified by the
- <parameter>typescript-path</parameter> parameter will
- automatically be created if it does not yet exist. Only the
- final directory in the path will be created - if other
- directories earlier in the path do not exist, automatic
- creation will fail, and an error will be logged.</para>
- <para><emphasis>This parameter is optional.</emphasis> By
- default, the directory specified by the
- <parameter>typescript-path</parameter> parameter will
- not automatically be created, and attempts to record
- typescripts in a non-existent directory will be logged as
- errors.</para>
- <para>This parameter only has an effect if typescript recording
- is enabled. If the <parameter>typescript-path</parameter> is
- not specified, recording of typescripts will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>typescript-name</parameter></entry>
- <entry>
- <para>The base filename to use when determining the names for
- the data and timing files of the typescript. <emphasis>This
- parameter is optional.</emphasis> If omitted, the value
- "typescript" will be used instead.</para>
- <para>Each typescript consists of two files which are created
- within the directory specified by
- <parameter>typescript-path</parameter>:
- <filename><replaceable>NAME</replaceable></filename>,
- which contains the raw text data, and
- <filename><replaceable>NAME</replaceable>.timing</filename>,
- which contains timing information, where
- <replaceable>NAME</replaceable> is the value provided
- for the <parameter>typescript-name</parameter>
- parameter.</para>
- <para>This parameter only has an effect if typescript recording
- is enabled. If the <parameter>typescript-path</parameter> is
- not specified, recording of typescripts will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="telnet-recording">
- <title>Graphical session recording</title>
- <para>In addition to text-based recordings, telnet sessions can be recorded
- graphically. These recordings take the form of Guacamole protocol dumps and are
- recorded automatically to a specified directory. Recordings can be subsequently
- translated to a normal video stream using the <command>guacenc</command> utility
- provided with guacamole-server.</para>
- <para>For example, to produce a video called "<replaceable>NAME</replaceable>.m4v"
- from the recording "<replaceable>NAME</replaceable>", you would run:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guacenc <replaceable>/path/to/recording/NAME</replaceable></userinput></screen>
- </informalexample>
- <para>The <command>guacenc</command> utility has additional options for overriding
- default behavior, including tweaking the output format, which are documented in
- detail within the manpage:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>man guacenc</userinput></screen>
- </informalexample>
- <para>If recording of key events is explicitly enabled using the
- <parameter>recording-include-keys</parameter> parameter, recordings can also
- be translated into human-readable interpretations of the keys pressed during the
- session using the <command>guaclog</command> utility. The usage of
- <command>guaclog</command> is analogous to <command>guacenc</command>, and
- results in the creation of a new text file containing the interpreted
- events:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guaclog <replaceable>/path/to/recording/NAME</replaceable></userinput><computeroutput>
-guaclog: INFO: Guacamole input log interpreter (guaclog) version 1.3.0
-guaclog: INFO: 1 input file(s) provided.
-guaclog: INFO: Writing input events from "<replaceable>/path/to/recording/NAME</replaceable>" to "<replaceable annotations="">/path/to/recording/NAME</replaceable>.txt" ...
-guaclog: INFO: All files interpreted successfully.</computeroutput>
-<prompt>$</prompt> </screen>
- </informalexample>
- <important>
- <para>Guacamole will never overwrite an existing recording. If necessary, a
- numeric suffix like ".1", ".2", ".3", etc. will be appended to
- <replaceable>NAME</replaceable> to avoid overwriting an existing
- recording. If even appending a numeric suffix does not help, the session
- will simply not be recorded.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>telnet</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>recording-path</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>telnet</primary>
- <secondary>graphical recording</secondary>
- </indexterm>The directory in which screen recording files
- should be created. <emphasis>If a graphical recording needs
- to be created, then this parameter is
- required.</emphasis> Specifying this parameter enables
- graphical screen recording. If this parameter is omitted, no
- graphical recording will be created.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>create-recording-path</parameter></entry>
- <entry>
- <para>If set to "true", the directory specified by the
- <parameter>recording-path</parameter> parameter will
- automatically be created if it does not yet exist. Only the
- final directory in the path will be created - if other
- directories earlier in the path do not exist, automatic
- creation will fail, and an error will be logged.</para>
- <para><emphasis>This parameter is optional.</emphasis> By
- default, the directory specified by the
- <parameter>recording-path</parameter> parameter will not
- automatically be created, and attempts to create recordings
- within a non-existent directory will be logged as
- errors.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-name</parameter></entry>
- <entry>
- <para>The filename to use for any created recordings.
- <emphasis>This parameter is optional.</emphasis> If
- omitted, the value "recording" will be used instead.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-output</parameter></entry>
- <entry>
- <para>If set to "true", graphical output and other data normally
- streamed from server to client will be excluded from the
- recording, producing a recording which contains only user
- input events. <emphasis>This parameter is
- optional.</emphasis> If omitted, graphical output will
- be included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-mouse</parameter></entry>
- <entry>
- <para>If set to "true", user mouse events will be excluded from
- the recording, producing a recording which lacks a visible
- mouse cursor. <emphasis>This parameter is
- optional.</emphasis> If omitted, mouse events will be
- included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-include-keys</parameter></entry>
- <entry>
- <para>If set to "true", user key events will be included in the
- recording. The recording can subsequently be passed through
- the <command>guaclog</command> utility to produce a
- human-readable interpretation of the keys pressed during the
- session. <emphasis>This parameter is optional.</emphasis> If
- omitted, key events will be not included in the
- recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="telnet-disable-clipboard">
- <title>Disabling clipboard access</title>
- <para>Guacamole provides bidirectional access to the terminal clipboard by default
- for telnet connections. This behavior can be overridden on a per-connection
- basis with the <parameter>disable-copy</parameter> and
- <parameter>disable-paste</parameter> parameters.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>telnet</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>disable-copy</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>disable clipboard</primary>
- </indexterm><indexterm>
- <primary>telnet</primary>
- <secondary>disable clipboard</secondary>
- </indexterm>If set to "true", text copied within the telnet
- session will not be accessible by the user at the browser
- side of the Guacamole session, and will be usable only
- within the terminal. This parameter is optional. By default,
- the user will be given access to the copied text.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>disable-paste</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>disable clipboard</primary>
- </indexterm><indexterm>
- <primary>telnet</primary>
- <secondary>disable clipboard</secondary>
- </indexterm>If set to "true", text copied at the browser
- side of the Guacamole session will not be accessible within
- the telnet session. This parameter is optional. By default,
- the user will be able to paste data from outside the browser
- within the terminal.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="telnet-wake-on-lan">
- <title>Wake-on-LAN Configuration</title>
- <para>Guacamole implements the support to send a "magic wake-on-lan
- packet" to a remote host prior to attempting to establish a
- connection with the host. The below parameters control the
- behavior of this functionality, which is disabled by default.
- </para>
- <important>
- <para>There are several factors that can impact the ability
- of Wake-on-LAN (WoL) to function correctly, many of which
- are outside the scope of Guacamole configuration. If you
- are configuring WoL within Guacamole you should also be
- familiar with the other components that need to be
- configured in order for it to function correctly.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>telnet</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>wol-send-packet</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-send-packet</primary>
- </indexterm><indexterm>
- <primary>telnet</primary>
- <secondary>wol-send-packet</secondary>
- </indexterm>If set to "true", Guacamole will
- attempt to send the Wake-On-LAN packet prior
- to establishing a connection. This parameter
- is optional. By default, Guacamole will
- not send the WoL packet. Enabling this
- option requires that the
- <parameter>wol-mac-addr</parameter>
- parameter also be configured, otherwise
- the WoL packet will not be sent.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-mac-addr</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-mac-addr</primary>
- </indexterm><indexterm>
- <primary>telnet</primary>
- <secondary>wol-mac-addr</secondary>
- </indexterm>This parameter configures the
- MAC address that Guacamole will use in
- the magic WoL packet to attempt to wake
- the remote system. If
- <parameter>wol-send-packet</parameter>
- is enabled, this parameter is required
- or else the WoL packet will not be sent.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-broadcast-addr</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-broadcast-addr</primary>
- </indexterm><indexterm>
- <primary>telnet</primary>
- <secondary>wol-broadcast-addr</secondary>
- </indexterm>This parameter configures the
- IPv4 broadcast address or IPv6 multicast
- address that Guacamole will send the
- WoL packet to in order to wake the host.
- This parameter is optional. If no value
- is provided, the default local IPv4 broadcast
- address (255.255.255.255) will be used.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-udp-port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-udp-port</primary>
- </indexterm><indexterm>
- <primary>telnet</primary>
- <secondary>wol-udp-port</secondary>
- </indexterm>This parameter configures the
- UDP port that will be set in the WoL packet.
- In most cases the UDP port isn't processed
- by the system that will be woken up; however,
- there are certain cases where it is useful
- for the port to be set, as in situations
- where a router is listening for the packet
- and can make routing decisions depending
- upon the port that is used. If not
- configured the default UDP port 9 will be
- used.
- </para>
- </entry>
- </row>
- <row>
- <entry><parameter>wol-wait-time</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>wol-wait-time</primary>
- </indexterm><indexterm>
- <primary>telnet</primary>
- <secondary>wol-wait-time</secondary>
- </indexterm>By default after the WoL packet
- is sent Guacamole will attempt immediately
- to connect to the remote host. It may be
- desirable in certain scenarios to have
- Guacamole wait before the initial connection
- in order to give the remote system time to
- boot. Setting this parameter to a positive
- value will cause Guacamole to wait the specified
- number of seconds before attempting the initial
- connection. This parameter is optional.
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="adding-telnet">
- <title>Adding a telnet connection</title>
- <indexterm>
- <primary>telnet</primary>
- <secondary>adding</secondary>
- </indexterm>
- <para>If you are using the default authentication built into Guacamole, and you wish
- to grant access to a telnet connection to a particular user, you need to locate
- the <code><authorize></code> section for that user within your
- <filename>user-mapping.xml</filename>, and add a section like the following
- within it:</para>
- <programlisting><connection name="<replaceable>Unique Name</replaceable>">
- <protocol>telnet</protocol>
- <param name="hostname"><replaceable>localhost</replaceable></param>
- <param name="port"><replaceable>23</replaceable></param>
-</connection></programlisting>
- <para>If added exactly as above, a new connection named "<replaceable>Unique
- Name</replaceable>" will be available to the user associated with the
- <code><authorize></code> section containing it. The connection will use
- telnet to connect to <replaceable>localhost</replaceable> at port
- <replaceable>23</replaceable>. Naturally, you will want to change some or
- all of these values.</para>
- <para>As telnet is inherently insecure compared to SSH, you should use SSH instead
- wherever possible. If Guacamole is set up to use HTTPS then communication with
- the Guacamole <emphasis>client</emphasis> will be encrypted, but communication
- between guacd and the telnet server will still be unencrypted. You should not
- use telnet unless the network between guacd and the telnet server is
- trusted.</para>
- </section>
- </section>
- <section xml:id="kubernetes">
- <title>Kubernetes</title>
- <indexterm>
- <primary>Kubernetes</primary>
- </indexterm>
- <para>Kubernetes provides an API for attaching to the console of a container over the
- network. As with SSH and telnet, Guacamole's Kubernetes support emulates a terminal
- on the server side which renders to the Guacamole client's display.</para>
- <para>Kubernetes support for Guacamole is provided by the
- <package>libguac-client-kubernetes</package> library, which will be installed as
- part of guacamole-server if the required dependencies are present during the
- build.</para>
- <section xml:id="kubernetes-network-parameters">
- <title>Network/Container parameters</title>
- <para>Attaching to a Kubernetes container requires the hostname or IP address of the
- Kubernetes server and the name of the pod containing the container in question.
- By default, Guacamole will attach to the first container in the pod. If there
- are multiple containers in the pod, you may wish to also specify the container
- name.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>Kubernetes</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>hostname</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>hostname</secondary>
- </indexterm>The hostname or IP address of the Kubernetes
- server that Guacamole should connect to.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>port</secondary>
- </indexterm>The port the Kubernetes server is listening on
- for API connections. <emphasis>This parameter is
- optional.</emphasis> If omitted, port 8080 will be used
- by default.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>namespace</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>namespace</secondary>
- </indexterm>The name of the Kubernetes namespace of the pod
- containing the container being attached to. <emphasis>This
- parameter is optional.</emphasis> If omitted, the
- namespace "default" will be used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>pod</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>pod</secondary>
- </indexterm>The name of the Kubernetes pod containing with
- the container being attached to.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>container</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>container</secondary>
- </indexterm>The name of the container to attach to.
- <emphasis>This parameter is optional.</emphasis> If
- omitted, the first container in the pod will be used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>exec-command</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>command</secondary>
- </indexterm>The command to run within the container, with
- input and output attached to this command's process.
- <emphasis>This parameter is optional.</emphasis> If
- omitted, no command will be run, and input/output will
- instead be attached to the main process of the
- container.</para>
- <para>When this parameter is specified, the behavior of the
- connection is analogous to running <command>kubectl
- exec</command>. When omitted, the behavior is analogous
- to running <command>kubectl attach</command>.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="kubernetes-authentication">
- <title>Authentication and SSL/TLS</title>
- <para>If enabled, Kubernetes uses SSL/TLS for both encryption and authentication.
- Standard SSL/TLS client authentication requires both a client certificate and
- client key, which Guacamole will use to identify itself to the Kubernetes
- server. If the certificate used by Kubernetes is self-signed or signed by a
- non-standard certificate authority, the certificate for the certificate
- authority will also be needed.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>Kubernetes</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>use-ssl</parameter></entry>
- <entry>
- <para>If set to "true", SSL/TLS will be used to connect to the
- Kubernetes server. <emphasis>This parameter is
- optional.</emphasis> By default, SSL/TLS will not be
- used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>client-cert</parameter></entry>
- <entry>
- <para>The certificate to use if performing SSL/TLS client
- authentication to authenticate with the Kubernetes server,
- in PEM format. <emphasis>This parameter is
- optional.</emphasis> If omitted, SSL client
- authentication will not be performed.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>client-key</parameter></entry>
- <entry>
- <para>The key to use if performing SSL/TLS client authentication
- to authenticate with the Kubernetes server, in PEM format.
- <emphasis>This parameter is optional.</emphasis> If
- omitted, SSL client authentication will not be
- performed</para>
- </entry>
- </row>
- <row>
- <entry><parameter>ca-cert</parameter></entry>
- <entry>
- <para>The certificate of the certificate authority that signed
- the certificate of the Kubernetes server, in PEM format.
- <emphasis>This parameter is optional.</emphasis> If
- omitted, verification of the Kubernetes server certificate
- will use only system-wide certificate authorities. </para>
- </entry>
- </row>
- <row>
- <entry><parameter>ignore-cert</parameter></entry>
- <entry>
- <para>If set to "true", the validity of the SSL/TLS certificate
- used by the Kubernetes server will be ignored if it cannot
- be validated. <emphasis>This parameter is
- optional.</emphasis> By default, SSL/TLS certificates
- are validated.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="kubernetes-display-settings">
- <title>Display settings</title>
- <para>Guacamole's Kubernetes support provides a display, but not in the same sense
- as a remote desktop protocol like VNC or RDP. The display is a terminal
- emulator, and thus provides options for configuring the font used and its size.
- In this case, <emphasis>the chosen font must be installed on the
- server</emphasis>, as it is the server that will handle rendering of
- characters to the terminal display, not the client.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>Kubernetes</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>color-scheme</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>color scheme</secondary>
- </indexterm>The color scheme to use for the terminal
- emulator used by Kubernetes connections. It consists of a
- semicolon-separated series of name-value pairs. Each
- name-value pair is separated by a colon and assigns a value
- to a color in the terminal emulator palette. For example, to
- use blue text on white background by default, and change the
- red color to a purple shade, you would specify:</para>
- <informalexample>
- <programlisting>foreground: rgb:00/00/ff;
-background: rgb:ff/ff/ff;
-color9: rgb:80/00/80</programlisting>
- </informalexample>
- <para>This format is similar to the color configuration format
- used by Xterm, so Xterm color configurations can be easily
- adapted for Guacamole. This parameter is optional. If not
- specified, Guacamole will render text as gray over a black
- background.</para>
- <para>Possible color names are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>foreground</constant></term>
- <listitem>
- <para>Set the default foreground color.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>background</constant></term>
- <listitem>
- <para>Set the default background color.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>color<n></constant></term>
- <listitem>
- <para>Set the color at index <code><n></code>
- on the Xterm 256-color palette. For example,
- <code>color9</code> refers to the red color.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Possible color values are:</para>
- <variablelist>
- <varlistentry>
- <term><constant>rgb:RR/GG/BB</constant></term>
- <listitem>
- <para>Use the specified color in RGB format, with
- each component in hexadecimal. For example,
- <code>rgb:ff/00/00</code> specifies the color red.
- Note that each hexadecimal component can be one to
- four digits, but the effective values are always
- zero-extended or truncated to two digits; for
- example, <code>rgb:f/8/0</code>,
- <code>rgb:f0/80/00</code>, and
- <code>rgb:f0f/808/00f</code> all refer to the same
- effective color.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>color<n></constant></term>
- <listitem>
- <para>Use the color currently assigned to index
- <code><n></code> on the Xterm 256-color
- palette. For example, <code>color9</code>
- specifies the current red color. Note that the
- color value is used rather than the color
- reference, so if <code>color9</code> is changed
- later in the color scheme configuration, that new
- color will not be reflected in this
- assignment.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>For backward compatibility, Guacamole will also accept
- four special values as the color scheme parameter:</para>
- <variablelist>
- <varlistentry>
- <term><constant>black-white</constant></term>
- <listitem>
- <para>Black text over a white background.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>gray-black</constant></term>
- <listitem>
- <para>Gray text over a black background. This is the
- default color scheme.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>green-black</constant></term>
- <listitem>
- <para>Green text over a black background.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>white-black</constant></term>
- <listitem>
- <para>White text over a black background.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </entry>
- </row>
- <row>
- <entry><parameter>font-name</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>font</secondary>
- </indexterm>The name of the font to use. This parameter is
- optional. If not specified, the default of "monospace" will
- be used instead.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>font-size</parameter></entry>
- <entry>
- <para>The size of the font to use, in points. This parameter is
- optional. If not specified, the default of 12 will be used
- instead.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>read-only</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>read-only</secondary>
- </indexterm>Whether this connection should be read-only. If
- set to "true", no input will be accepted on the connection
- at all. Users will only see the console of the Kubernetes
- container. <emphasis>This parameter is optional.</emphasis>
- If omitted, the connection will not be read-only.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>scrollback</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>scrollback</secondary>
- </indexterm>The maximum number of rows to allow within the
- terminal scrollback buffer. This parameter is optional. If
- not specified, the scrollback buffer will be limited to a
- maximum of 1000 rows.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="kubernetes-terminal-behavior">
- <title>Controlling terminal behavior</title>
- <para>In most cases, the default behavior for a terminal works without modification.
- However, when connecting to certain systems, particularly operating systems
- other than Linux, the terminal behavior may need to be tweaked to allow it to
- operate properly. The settings in this section control that behavior.</para>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>Kubernetes</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>backspace</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>backspace</secondary>
- </indexterm>This parameter controls the ASCII code that the
- backspace key sends to the remote system. Under most
- circumstances this should not need to be adjusted; however,
- if, when pressing the backspace key, you see control
- characters (often either ^? or ^H) instead of seeing the
- text erased, you may need to adjust this parameter. By
- default the terminal sends ASCII code 127 (Delete) if this
- option is not set.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>terminal-type</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>terminal type</secondary>
- </indexterm>This parameter sets the terminal emulator type
- string that is passed to the Kubernetes server. This
- parameter is optional. If not specified,
- "<code>linux</code>" is used as the terminal
- emulator type by default.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="kubernetes-typescripts">
- <title>Text session recording (typescripts)</title>
- <para>The full, raw text content of Kubernetes sessions, including timing
- information, can be recorded automatically to a specified directory. This
- recording, also known as a "typescript", will be written to two files within the
- directory specified by <parameter>typescript-path</parameter>:
- <filename><replaceable>NAME</replaceable></filename>, which contains the
- raw text data, and <filename><replaceable>NAME</replaceable>.timing</filename>,
- which contains timing information, where <replaceable>NAME</replaceable> is the
- value provided for the <parameter>typescript-name</parameter> parameter.</para>
- <para>This format is compatible with the format used by the standard UNIX
- <command>script</command> command, and can be replayed using
- <command>scriptreplay</command> (if installed). For example, to replay a
- typescript called "<replaceable>NAME</replaceable>", you would run:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>scriptreplay <replaceable>NAME</replaceable>.timing <replaceable>NAME</replaceable></userinput></screen>
- </informalexample>
- <important>
- <para>Guacamole will never overwrite an existing recording. If necessary, a
- numeric suffix like ".1", ".2", ".3", etc. will be appended to
- <replaceable>NAME</replaceable> to avoid overwriting an existing
- recording. If even appending a numeric suffix does not help, the session
- will simply not be recorded.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>Kubernetes</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>typescript-path</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>typescripts</secondary>
- </indexterm><indexterm>
- <primary>Kubernetes</primary>
- <secondary>text recording</secondary>
- </indexterm>The directory in which typescript files should
- be created. <emphasis>If a typescript needs to be recorded,
- this parameter is required.</emphasis> Specifying this
- parameter enables typescript recording. If this parameter is
- omitted, no typescript will be recorded.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>create-typescript-path</parameter></entry>
- <entry>
- <para>If set to "true", the directory specified by the
- <parameter>typescript-path</parameter> parameter will
- automatically be created if it does not yet exist. Only the
- final directory in the path will be created - if other
- directories earlier in the path do not exist, automatic
- creation will fail, and an error will be logged.</para>
- <para><emphasis>This parameter is optional.</emphasis> By
- default, the directory specified by the
- <parameter>typescript-path</parameter> parameter will
- not automatically be created, and attempts to record
- typescripts in a non-existent directory will be logged as
- errors.</para>
- <para>This parameter only has an effect if typescript recording
- is enabled. If the <parameter>typescript-path</parameter> is
- not specified, recording of typescripts will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>typescript-name</parameter></entry>
- <entry>
- <para>The base filename to use when determining the names for
- the data and timing files of the typescript. <emphasis>This
- parameter is optional.</emphasis> If omitted, the value
- "typescript" will be used instead.</para>
- <para>Each typescript consists of two files which are created
- within the directory specified by
- <parameter>typescript-path</parameter>:
- <filename><replaceable>NAME</replaceable></filename>,
- which contains the raw text data, and
- <filename><replaceable>NAME</replaceable>.timing</filename>,
- which contains timing information, where
- <replaceable>NAME</replaceable> is the value provided
- for the <parameter>typescript-name</parameter>
- parameter.</para>
- <para>This parameter only has an effect if typescript recording
- is enabled. If the <parameter>typescript-path</parameter> is
- not specified, recording of typescripts will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="kubernetes-recording">
- <title>Graphical session recording</title>
- <para>In addition to text-based recordings, Kubernetes sessions can be recorded
- graphically. These recordings take the form of Guacamole protocol dumps and are
- recorded automatically to a specified directory. Recordings can be subsequently
- translated to a normal video stream using the <command>guacenc</command> utility
- provided with guacamole-server.</para>
- <para>For example, to produce a video called "<replaceable>NAME</replaceable>.m4v"
- from the recording "<replaceable>NAME</replaceable>", you would run:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guacenc <replaceable>/path/to/recording/NAME</replaceable></userinput></screen>
- </informalexample>
- <para>The <command>guacenc</command> utility has additional options for overriding
- default behavior, including tweaking the output format, which are documented in
- detail within the manpage:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>man guacenc</userinput></screen>
- </informalexample>
- <para>If recording of key events is explicitly enabled using the
- <parameter>recording-include-keys</parameter> parameter, recordings can also
- be translated into human-readable interpretations of the keys pressed during the
- session using the <command>guaclog</command> utility. The usage of
- <command>guaclog</command> is analogous to <command>guacenc</command>, and
- results in the creation of a new text file containing the interpreted
- events:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guaclog <replaceable>/path/to/recording/NAME</replaceable></userinput><computeroutput>
-guaclog: INFO: Guacamole input log interpreter (guaclog) version 1.3.0
-guaclog: INFO: 1 input file(s) provided.
-guaclog: INFO: Writing input events from "<replaceable>/path/to/recording/NAME</replaceable>" to "<replaceable annotations="">/path/to/recording/NAME</replaceable>.txt" ...
-guaclog: INFO: All files interpreted successfully.</computeroutput>
-<prompt>$</prompt> </screen>
- </informalexample>
- <important>
- <para>Guacamole will never overwrite an existing recording. If necessary, a
- numeric suffix like ".1", ".2", ".3", etc. will be appended to
- <replaceable>NAME</replaceable> to avoid overwriting an existing
- recording. If even appending a numeric suffix does not help, the session
- will simply not be recorded.</para>
- </important>
- <informaltable frame="all">
- <indexterm>
- <primary>parameters</primary>
- <secondary>Kubernetes</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>recording-path</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>Kubernetes</primary>
- <secondary>graphical recording</secondary>
- </indexterm>The directory in which screen recording files
- should be created. <emphasis>If a graphical recording needs
- to be created, then this parameter is
- required.</emphasis> Specifying this parameter enables
- graphical screen recording. If this parameter is omitted, no
- graphical recording will be created.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>create-recording-path</parameter></entry>
- <entry>
- <para>If set to "true", the directory specified by the
- <parameter>recording-path</parameter> parameter will
- automatically be created if it does not yet exist. Only the
- final directory in the path will be created - if other
- directories earlier in the path do not exist, automatic
- creation will fail, and an error will be logged.</para>
- <para><emphasis>This parameter is optional.</emphasis> By
- default, the directory specified by the
- <parameter>recording-path</parameter> parameter will not
- automatically be created, and attempts to create recordings
- within a non-existent directory will be logged as
- errors.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-name</parameter></entry>
- <entry>
- <para>The filename to use for any created recordings.
- <emphasis>This parameter is optional.</emphasis> If
- omitted, the value "recording" will be used instead.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-output</parameter></entry>
- <entry>
- <para>If set to "true", graphical output and other data normally
- streamed from server to client will be excluded from the
- recording, producing a recording which contains only user
- input events. <emphasis>This parameter is
- optional.</emphasis> If omitted, graphical output will
- be included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-exclude-mouse</parameter></entry>
- <entry>
- <para>If set to "true", user mouse events will be excluded from
- the recording, producing a recording which lacks a visible
- mouse cursor. <emphasis>This parameter is
- optional.</emphasis> If omitted, mouse events will be
- included in the recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>recording-include-keys</parameter></entry>
- <entry>
- <para>If set to "true", user key events will be included in the
- recording. The recording can subsequently be passed through
- the <command>guaclog</command> utility to produce a
- human-readable interpretation of the keys pressed during the
- session. <emphasis>This parameter is optional.</emphasis> If
- omitted, key events will be not included in the
- recording.</para>
- <para>This parameter only has an effect if graphical recording
- is enabled. If the <parameter>recording-path</parameter> is
- not specified, graphical session recording will be disabled,
- and this parameter will be ignored.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="adding-kubernetes">
- <title>Adding a Kubernetes connection</title>
- <indexterm>
- <primary>Kubernetes</primary>
- <secondary>adding</secondary>
- </indexterm>
- <para>If you are using the default authentication built into Guacamole, and you wish
- to grant access to a Kubernetes connection to a particular user, you need to
- locate the <code><authorize></code> section for that user within your
- <filename>user-mapping.xml</filename>, and add a section like the following
- within it:</para>
- <programlisting><connection name="<replaceable>Unique Name</replaceable>">
- <protocol>kubernetes</protocol>
- <param name="hostname"><replaceable>localhost</replaceable></param>
- <param name="pod"><replaceable>mypod</replaceable></param>
-</connection></programlisting>
- <para>If added exactly as above, a new connection named "<replaceable>Unique
- Name</replaceable>" will be available to the user associated with the
- <code><authorize></code> section containing it. The connection will
- connect to the Kubernetes server running on <replaceable>localhost</replaceable>
- and attach to the first container of the pod
- <replaceable>mypod</replaceable>.</para>
- </section>
- </section>
- <section xml:id="parameter-tokens">
- <title>Parameter tokens</title>
- <indexterm>
- <primary>tokens</primary>
- </indexterm>
- <para>The values of connection parameters can contain "tokens" which will be replaced by
- Guacamole when used. These tokens allow the values of connection parameters to vary
- dynamically by the user using the connection, and provide a simple means of
- forwarding authentication information without storing that information in the
- connection configuration itself, so long as the remote desktop connection uses the
- same credentials as Guacamole.</para>
- <para>Each token is of the form <varname>${<replaceable>TOKEN_NAME</replaceable>}</varname> or
- <varname>${<replaceable>TOKEN_NAME</replaceable>:<replaceable>MODIFIER</replaceable>}</varname>,
- where <replaceable>TOKEN_NAME</replaceable> is some descriptive name for the value the
- token represents, and the optional <replaceable>MODIFIER</replaceable> is one of the
- modifiers documented below to dynamically modify the token. Tokens with no corresponding
- value will never be replaced, but should you need such text within your connection
- parameters, and wish to guarantee that this text will not be replaced with a token value,
- you can escape the token by adding an additional leading "$", as in "$${TOKEN_NAME}".</para>
- <variablelist>
- <varlistentry>
- <term><varname>${GUAC_USERNAME}</varname></term>
- <listitem>
- <para>The username of the current Guacamole user. When a user accesses a
- connection, this token will be dynamically replaced with the username
- they provided when logging in to Guacamole.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><varname>${GUAC_PASSWORD}</varname></term>
- <listitem>
- <para>The password of the current Guacamole user. When a user accesses a
- connection, this token will be dynamically replaced with the password
- they used when logging in to Guacamole.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><varname>${GUAC_CLIENT_ADDRESS}</varname></term>
- <listitem>
- <para>The IPv4 or IPv6 address of the current Guacamole user. This will be
- the address of the client side of the HTTP connection to the Guacamole
- server at the time the current user logged in.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><varname>${GUAC_CLIENT_HOSTNAME}</varname></term>
- <listitem>
- <para>The hostname of the current Guacamole user. This will be the hostname
- of the client side of the HTTP connection to the Guacamole server at the
- time the current user logged in. If no such hostname can be determined,
- the IPv4 or IPv6 address will be used instead, and this token will be
- equivalent to <varname>${GUAC_CLIENT_ADDRESS}</varname>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><varname>${GUAC_DATE}</varname></term>
- <listitem>
- <para>The current date in the local time zone of the Guacamole server. This
- will be written in "YYYYMMDD" format, where "YYYY" is the year, "MM" is
- the month number, and "DD" is the day of the month, all zero-padded.
- When a user accesses a connection, this token will be dynamically
- replaced with the date that the connection began.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><varname>${GUAC_TIME}</varname></term>
- <listitem>
- <para>The current time in the local time zone of the Guacamole server. This
- will be written in "HHMMSS" format, where "HH" is hours in 24-hour time,
- "MM" is minutes, and "SS" is seconds, all zero-padded. When a user
- accesses a connection, this token will be dynamically replaced with the
- time that the connection began.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Note that these tokens are replaced dynamically each time a connection is used. If
- two different users access the same connection at the same time, both users will be
- connected independently of each other using different sets of connection
- parameters.</para>
- <section xml:id="token-modifiers">
- <title>Token modifiers</title>
- <indexterm>
- <primary>tokens</primary>
- <secondary>modifiers</secondary>
- </indexterm>
- <para>At times it can be useful to use the value provided by a token, but with slight
- modifications. These modifers are optionally specified at the end of the token,
- separated from the token name by a colon (:), in the format
- <varname>${TOKEN_NAME:<replaceable>MODIFIER</replaceable>}</varname>.The following
- modifiers are currently supported:</para>
- <variablelist>
- <varlistentry>
- <term><varname>LOWER</varname></term>
- <listitem>
- <para>Convert the entire value of the token to lower-case. This can be
- useful in situations where users log in to Guacamole with a mixed-case
- username, but a remote system requires the username be lower-case.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><varname>UPPER</varname></term>
- <listitem>
- <para>Convert the entire value of the token to upper-case.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="extension-tokens">
- <title>Extension-specific tokens</title>
- <indexterm>
- <primary>tokens</primary>
- <secondary>extension-specific</secondary>
- </indexterm>
- <para>Each extension can also implement its own arbitrary tokens that can dynamically
- fill in values provided by the extension. Within these extensions, attribute
- names are canonicalized into a standard format that consists of all capital
- letters separated by underscores.</para>
- <section xml:id="cas-tokens">
- <title>CAS Extension Tokens</title>
- <indexterm>
- <primary>tokens</primary>
- <secondary>cas</secondary>
- </indexterm>
- <para>The CAS extension will read attributes provided by the CAS server when
- a user is authenticated and will make those attributes available as
- tokens. The CAS server must be specifically configured to release certain
- attributes to the client (Guacamole), and configuration of that is outside
- the scope of this document. Any attribute that the CAS server is
- configured to release should be available to Guacamole as a token for
- use within a connection. The token name will be prepended with the
- <constant>CAS_</constant> prefix. A CAS server configured to release
- attributes <varname>firstname</varname>, <varname>lastname</varname>,
- <varname>email</varname>, and <varname>mobile</varname> would produce the
- following tokens:</para>
- <itemizedlist>
- <listitem>
- <para>
- <varname>${CAS_FIRSTNAME}</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>${CAS_LASTNAME}</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>${CAS_EMAIL}</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>${CAS_MOBILE}</varname>
- </para>
- </listitem>
- </itemizedlist>
- </section>
- <section xml:id="ldap-tokens">
- <title>LDAP Extension Tokens</title>
- <indexterm>
- <primary>tokens</primary>
- <secondary>ldap</secondary>
- </indexterm>
- <para>The LDAP extension will read user attributes provided by the LDAP
- server and specified in the <filename>guacamole.properties</filename>
- file. The attributes retrieved for a user are configured using the
- <parameter>ldap-user-attributes</parameter> parameter. The user must
- be able to read the attribute values from their own LDAP object.
- The token name will be prepended with the <constant>LDAP_</constant>
- prefix. As an example, configuring the following line in
- <filename>guacamole.properties</filename>:</para>
- <informalexample><programlisting>ldap-user-attributes: cn, givenName, sn, mobile, mail
- </programlisting></informalexample>
- <para>will produce the below tokens that can be used in connection
- parameters:</para>
- <itemizedlist>
- <listitem>
- <para>
- <varname>${LDAP_CN}</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>${LDAP_GIVENNAME}</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>${LDAP_SN}</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>${LDAP_MOBILE}</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>${LDAP_MAIL}</varname>
- </para>
- </listitem>
- </itemizedlist>
- </section>
- </section>
- </section>
- <section xml:id="parameter-prompting">
- <title>Parameter prompting</title>
- <para><indexterm>
- <primary>parameters</primary>
- <secondary>prompt</secondary>
- </indexterm>In certain situations Guacamole may determine that additional
- information is required in order to successfully open or continue a
- connection. In these scenarios guacd will send an instruction back to
- the client to retrieve that information, which will result in the user
- being prompted for those additional parameters.</para>
- <para>Currently the only parameters that will trigger this prompt to the
- user are authentication requests for the RDP and VNC protocols where
- authenticators were not provided as part of the connection configuration.
- </para>
- <important>
- <para>It is important to note that requests for parameters will only be
- generated in the case where that information has not already been
- provided as part of the connection. The user will never be asked for
- parameters that replace or override connection parameters where
- values have been configured as part of the connection, including
- authentication information. For example, if the configuration of
- a connection to a RDP server specifies a username and password,
- and that username or password is incorrect and results in an
- authentication failure, Guacamole will not prompt the user for
- additional credentials. For RDP servers where NLA is enforced,
- this will result in a connection failure. Other RDP servers may
- behave differently and give the user the ability to try other
- credentials, but this is outside the control of Guacamole -
- Guacamole will not override pre-configured values with input
- from the user.</para>
- </important>
- </section>
- </section>
- <section xml:id="guacd.conf">
- <title>Configuring guacd</title>
- <para><indexterm>
- <primary>guacd.conf</primary>
- </indexterm>guacd is configured with a configuration file called
- <filename>guacd.conf</filename>, by default located in
- <filename>/etc/guacamole</filename>. This file follows a simple, INI-like
- format:</para>
- <informalexample>
- <programlisting>#
-# guacd configuration file
-#
-
-[daemon]
-
-pid_file = /var/run/guacd.pid
-log_level = info
-
-[server]
-
-bind_host = localhost
-bind_port = 4822
-
-#
-# The following parameters are valid only if
-# guacd was built with SSL support.
-#
-
-[ssl]
-
-server_certificate = /etc/ssl/certs/guacd.crt
-server_key = /etc/ssl/private/guacd.key</programlisting>
- </informalexample>
- <para>Configuration options are given as parameter/value pairs, where the name of the
- parameter is specified on the left side of an "<code>=</code>", and the value is
- specified on the right. Each parameter must occur within a proper section, indicated by
- a section name within brackets. The names of these sections are important; it is the
- pairing of a section name with a parameter that constitutes the fully-qualified
- parameter being set.</para>
- <para>For the sake of documentation and readability, comments can be added anywhere within
- guacd.conf using "<code>#</code>" symbols. All text following a "<code>#</code>" until
- end-of-line will be ignored.</para>
- <para>If you need to include special characters within the value of a parameter, such as
- whitespace or any of the above symbols, you can do so by placing the parameter within
- double quotes:</para>
- <informalexample>
- <programlisting>[ssl]
-
-# Whitespace is legal within double quotes ...
-server_certificate = "/etc/ssl/my certs/guacd.crt"
-
-# ... as are other special symbols
-server_key = "/etc/ssl/#private/guacd.key"</programlisting>
- </informalexample>
- <para>Note that even within double quotes, some characters still have special meaning, such
- as the double quote itself or newline characters. If you need to include these, they
- must be "escaped" with a backslash:</para>
- <informalexample>
- <programlisting># Parameter value containing a double quote
-parameter = "some\"value"
-
-# Parameter value containing newline characters
-parameter2 = "line1\
-line2\
-line3"
-
-# Parameter value containing backslashes
-parameter3 = "c:\\windows\\path\\to\\file.txt"</programlisting>
- </informalexample>
- <para>Don't worry too much about the more complex formatting examples - they are only rarely
- necessary, and guacd will complain with parsing errors if the configuration file is
- somehow invalid. To ensure parameter values are entered correctly, just follow the
- following guidelines:</para>
- <orderedlist>
- <listitem>
- <para>If the value contains no special characters, just include it as-is.</para>
- </listitem>
- <listitem>
- <para>If the value contains any special characters (whitespace, newlines,
- <code>#</code>, <code>\</code>, or <code>"</code>), enclose the entire value
- within double quotes.</para>
- </listitem>
- <listitem>
- <para>If the value is enclosed within double quotes, escape newlines,
- <code>\</code>, and <code>"</code> with a backslash.</para>
- </listitem>
- </orderedlist>
- <table frame="all">
- <title>guacd.conf parameters</title>
- <indexterm>
- <primary>parameters</primary>
- <secondary>guacd.conf</secondary>
- </indexterm>
- <tgroup cols="3">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="1.85*"/>
- <colspec colname="c3" colnum="3" colwidth="5.55*"/>
- <thead>
- <row>
- <entry>Section</entry>
- <entry>Name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>daemon</parameter></entry>
- <entry><parameter>pid_file</parameter></entry>
- <entry>
- <para><indexterm>
- <primary><parameter>pid_file</parameter></primary>
- </indexterm>The name of the file in which the PID of the main guacd
- process should be written. This is mainly needed for startup
- scripts, which need to monitor the state of guacd, killing it if
- necessary. If this parameter is specified, the user running guacd
- must have sufficient permissions to create or modify the specified
- file, or startup will fail.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>daemon</parameter></entry>
- <entry><parameter>log_level</parameter></entry>
- <entry>
- <para><indexterm>
- <primary>logging</primary>
- <secondary>guacd</secondary>
- </indexterm><indexterm>
- <primary>guacd</primary>
- <secondary>logging</secondary>
- </indexterm><indexterm>
- <primary><parameter>log_level</parameter></primary>
- </indexterm>The maximum level at which guacd will log messages to
- syslog and, if running in the foreground, the console. If omitted,
- the default level of <constant>info</constant> will be used.</para>
- <para>Legal values are <constant>trace</constant>,
- <constant>debug</constant>, <constant>info</constant>,
- <constant>warning</constant>, and
- <constant>error</constant>.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>server</parameter></entry>
- <entry><parameter>bind_host</parameter></entry>
- <entry>
- <para><indexterm>
- <primary><parameter>bind_host</parameter></primary>
- </indexterm>The host that guacd should bind to when listening for
- connections. If unspecified, guacd will bind to localhost, and only
- connections from within the server hosting guacd will
- succeed.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>server</parameter></entry>
- <entry><parameter>bind_port</parameter></entry>
- <entry>
- <para><indexterm>
- <primary><parameter>bind_port</parameter></primary>
- </indexterm>The port that guacd should bind to when listening for
- connections. If unspecified, port 4822 will be used.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>ssl</parameter></entry>
- <entry><parameter>server_certificate</parameter></entry>
- <entry>
- <para><indexterm>
- <primary><parameter>server_certificate</parameter></primary>
- </indexterm>The filename of the certificate to use for SSL
- encryption of the Guacamole protocol. If this option is specified,
- SSL encryption will be enabled, and the Guacamole web application
- will need to be configured within
- <filename>guacamole.properties</filename> to use SSL as
- well.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>ssl</parameter></entry>
- <entry><parameter>server_key</parameter></entry>
- <entry>
- <para><indexterm>
- <primary><parameter>server_key</parameter></primary>
- </indexterm>The filename of the private key to use for SSL
- encryption of the Guacamole protocol. If this option is specified,
- SSL encryption will be enabled, and the Guacamole web application
- will need to be configured within
- <filename>guacamole.properties</filename> to use SSL as
- well.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>You can also affect the configuration of guacd with command-line options. If given,
- these options take precendence over the system-wide configuration file:</para>
- <variablelist>
- <varlistentry>
- <term><option>-b <replaceable>HOST</replaceable></option></term>
- <listitem>
- <para>Changes the host or address that guacd listens on.</para>
- <para>This corresponds to the <parameter>bind_host</parameter> parameter within
- the <parameter>server</parameter> section of
- <filename>guacd.conf</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><option>-l <replaceable>PORT</replaceable></option></term>
- <listitem>
- <para>Changes the port that guacd listens on (the default is port 4822).</para>
- <para>This corresponds to the <parameter>bind_port</parameter> parameter within
- the <parameter>server</parameter> section of
- <filename>guacd.conf</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><option>-p <replaceable>PIDFILE</replaceable></option></term>
- <listitem>
- <para>Causes guacd to write the PID of the daemon process to the specified file.
- This is useful for init scripts and is used by the provided init
- script.</para>
- <para>This corresponds to the <parameter>pid_file</parameter> parameter within
- the <parameter>daemon</parameter> section of
- <filename>guacd.conf</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><option>-L <replaceable>LEVEL</replaceable></option></term>
- <listitem>
- <para>Sets the maximum level at which guacd will log messages to syslog and, if
- running in the foreground, the console. Legal values are
- <constant>trace</constant>, <constant>debug</constant>,
- <constant>info</constant>, <constant>warning</constant>, and
- <constant>error</constant>. The default value is
- <constant>info</constant>.</para>
- <para>This corresponds to the <parameter>log_level</parameter> parameter within
- the <parameter>daemon</parameter> section of
- <filename>guacd.conf</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><option>-f</option></term>
- <listitem>
- <para>Causes guacd to run in the foreground, rather than automatically forking
- into the background.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>If guacd was built with support for SSL, data sent via the Guacamole protocol can be
- encrypted with SSL if an SSL certificate and private key are given with the following
- options:</para>
- <variablelist>
- <varlistentry>
- <term><option>-C <replaceable>CERTIFICATE</replaceable></option></term>
- <listitem>
- <para>The filename of the certificate to use for SSL encryption of the Guacamole
- protocol. If this option is specified, SSL encryption will be enabled, and
- the Guacamole web application will need to be configured within
- <filename>guacamole.properties</filename> to use SSL as well.</para>
- <para>This corresponds to the <parameter>server_certificate</parameter>
- parameter within the <parameter>ssl</parameter> section of
- <filename>guacd.conf</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><option>-K <replaceable>KEY</replaceable></option></term>
- <listitem>
- <para>The filename of the private key to use for SSL encryption of the Guacamole
- protocol. If this option is specified, SSL encryption will be enabled, and
- the Guacamole web application will need to be configured within
- <filename>guacamole.properties</filename> to use SSL as well.</para>
- <para>This corresponds to the <parameter>server_key</parameter> parameter within
- the <parameter>ssl</parameter> section of
- <filename>guacd.conf</filename>.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
-
-</chapter>
diff --git a/src/chapters/custom-auth.xml b/src/chapters/custom-auth.xml
deleted file mode 100644
index 481f98f..0000000
--- a/src/chapters/custom-auth.xml
+++ /dev/null
@@ -1,483 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="custom-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Custom authentication</title>
- <indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>authentication</primary>
- <secondary>custom</secondary>
- </indexterm>
- <para>Guacamole's authentication layer is designed to be extendable such that users can
- integrate Guacamole into existing authentication systems without having to resort to writing
- their own web application around the Guacamole API.</para>
- <para>The web application comes with a default authentication mechanism which uses an XML file
- to associate users with connections. Extensions for Guacamole that provide LDAP-based
- authentication or database-based authentication have also been developed.</para>
- <para>To demonstrate the principles involved, we will implement a very simple authentication
- extension which associates a single user/password pair with a single connection, with all
- this information saved in properties inside the <filename>guacamole.properties</filename>
- file.</para>
- <para>In general, all other authentication extensions for Guacamole will use the principles
- demonstrated here. This tutorial demonstrates the simplest way to create an authentication
- extension for Guacamole - an authentication extension that does not support management of
- users and connections via the web interface.</para>
- <section xml:id="custom-auth-model">
- <title>Guacamole's authentication model</title>
- <para>When you view any page in Guacamole, whether that be the login screen or the client
- interface, the page makes an authentication attempt with the web application, sending
- all available credentials. After entering your username and password, the exact same
- process occurs, except the web application receives the username and password as
- well.</para>
- <para>The web application handles this authentication attempt by collecting all credentials
- available and passing them to designated classes called "authentication providers".
- Given the set of credentials, authentication providers return a context object that
- provides restricted access to other users and connections, if any.</para>
- </section>
- <section xml:id="custom-auth-skeleton">
- <title>A Guacamole extension skeleton</title>
- <para>For simplicity's sake, and because this is how things are done upstream in the
- Guacamole project, we will use Maven to build our extension.</para>
- <para>The bare minimum required for a Guacamole authentication extension is a
- <filename>pom.xml</filename> file listing guacamole-ext as a dependency, a single
- .java file implementing our stub of an authentication provider, and a
- <filename>guac-manifest.json</filename> file describing the extension and pointing
- to our authentication provider class.</para>
- <para>In our stub, we won't actually do any authentication yet; we'll just universally
- reject all authentication attempts by returning <varname>null</varname> for any
- credentials given. You can verify that this is what happens by checking the server
- logs.</para>
- <example>
- <title>Barebones <filename>pom.xml</filename> required for a simple authentication
- extension.</title>
- <programlisting><project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
- http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-auth-tutorial</artifactId>
- <packaging>jar</packaging>
- <version>1.3.0</version>
- <name>guacamole-auth-tutorial</name>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
-
- <build>
- <plugins>
-
- <!-- Written for 1.6 -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.3</version>
- <configuration>
- <source>1.6</source>
- <target>1.6</target>
- </configuration>
- </plugin>
-
- </plugins>
- </build>
-
- <dependencies>
-
- <!-- Guacamole Extension API -->
- <dependency>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-ext</artifactId>
- <version>1.3.0</version>
- <scope>provided</scope>
- </dependency>
-
- </dependencies>
-
-</project></programlisting>
- </example>
- <para>We won't need to update this <filename>pom.xml</filename> throughout the rest of the
- tutorial. Even after adding new files, Maven will just find them and compile as
- necessary.</para>
- <para>Naturally, we need the actual authentication extension skeleton code. While you can
- put this in whatever file and package you want, for the sake of this tutorial, we will
- assume you are using
- <classname>org.apache.guacamole.auth.TutorialAuthenticationProvider</classname>.</para>
- <example>
- <title>A skeleton <classname>TutorialAuthenticationProvider</classname></title>
- <programlisting>package org.apache.guacamole.auth;
-
-import java.util.Map;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.net.auth.simple.SimpleAuthenticationProvider;
-import org.apache.guacamole.net.auth.Credentials;
-import org.apache.guacamole.protocol.GuacamoleConfiguration;
-
-/**
- * Authentication provider implementation intended to demonstrate basic use
- * of Guacamole's extension API. The credentials and connection information for
- * a single user are stored directly in guacamole.properties.
- */
-public class TutorialAuthenticationProvider extends SimpleAuthenticationProvider {
-
- @Override
- public String getIdentifier() {
- return "tutorial";
- }
-
- @Override
- public Map<String, GuacamoleConfiguration>
- getAuthorizedConfigurations(Credentials credentials)
- throws GuacamoleException {
-
- // Do nothing ... yet
- return null;
-
- }
-
-}</programlisting>
- </example>
- <para>To conform with Maven, this skeleton file must be placed within
- <filename>src/main/java/org/apache/guacamole/auth</filename> as
- <filename>TutorialAuthenticationProvider.java</filename>.</para>
- <para>Notice how simple the authentication provider is. The
- <classname>SimpleAuthenticationProvider</classname> base class simplifies the
- <classname>AuthenticationProvider</classname> interface, requiring nothing more than
- a unique identifier (we will use "tutorial") and a single
- <methodname>getAuthorizedConfigurations()</methodname> implementation, which must
- return a <classname>Map</classname> of <classname>GuacamoleConfiguration</classname>
- each associated with some arbitrary unique ID. This unique ID will be presented to the
- user in the connection list after they log in.</para>
- <para>For now, <methodname>getAuthorizedConfigurations()</methodname> will just return
- <varname>null</varname>. This will cause Guacamole to report an invalid login for
- every attempt. Note that there is a difference in semantics between returning an empty
- map and returning <varname>null</varname>, as the former indicates the credentials are
- authorized but simply have no associated configurations, while the latter indicates the
- credentials are not authorized at all.</para>
- <para>The only remaining piece for the overall skeleton to be complete is a
- <filename>guac-manifest.json</filename> file. <emphasis>This file is absolutely
- required for all Guacamole extensions.</emphasis> The
- <filename>guac-manifest.json</filename> format is described in more detail in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="guacamole-ext"/>. It provides
- for quite a few properties, but for our authentication extension we are mainly
- interested in the Guacamole version sanity check (to make sure an extension built for
- the API of Guacamole version X is not accidentally used against version Y) and telling
- Guacamole where to find our authentication provider class.</para>
- <para>The Guacamole extension format requires that <filename>guac-manifest.json</filename>
- be placed in the root directory of the extension <filename>.jar</filename> file. To
- accomplish this with Maven, we place it within the
- <filename>src/main/resources</filename> directory. Maven will automatically pick it
- up during the build and include it within the <filename>.jar</filename>.</para>
- <example>
- <title>The required <filename>guac-manifest.json</filename></title>
- <programlisting>{
-
- "guacamoleVersion" : "1.3.0",
-
- "name" : "Tutorial Authentication Extension",
- "namespace" : "guac-auth-tutorial",
-
- "authProviders" : [
- "org.apache.guacamole.auth.TutorialAuthenticationProvider"
- ]
-
-}</programlisting>
- </example>
- </section>
- <section xml:id="custom-auth-building">
- <title>Building the extension</title>
- <para>Once all three of the above files are in place, the extension will build, and can even
- be installed within Guacamole (see <xref xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="custom-auth-installing"/> at the end of this chapter), even though it is
- just a skeleton at this point. It won't do anything yet other than reject all
- authentication attempts, but it's good to at least try building the extension to make
- sure nothing is missing and that all steps have been followed correctly so far:</para>
- <informalexample>
- <screen><prompt>$</prompt> mvn package
-<computeroutput>[INFO] Scanning for projects...
-[INFO] ------------------------------------------------------------------------
-[INFO] Building guacamole-auth-tutorial 1.3.0
-[INFO] ------------------------------------------------------------------------
-...
-[INFO] ------------------------------------------------------------------------
-[INFO] BUILD SUCCESS
-[INFO] ------------------------------------------------------------------------
-[INFO] Total time: 2.345 s
-[INFO] Finished at: 2015-12-16T13:39:00-08:00
-[INFO] Final Memory: 14M/138M
-[INFO] ------------------------------------------------------------------------</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>Assuming you see the "<computeroutput>BUILD SUCCESS</computeroutput>" message when you
- build the extension, there will be a new file,
- <filename>target/guacamole-auth-tutorial-1.3.0.jar</filename>, which can be
- installed within Guacamole and tested. If you changed the name or version of the project
- in the <filename>pom.xml</filename> file, the name of this new <filename>.jar</filename>
- file will be different, but it can still be found within
- <filename>target/</filename>.</para>
- </section>
- <section xml:id="custom-auth-config">
- <title>Configuration and authentication</title>
- <para>Once we receive credentials, we need to validate those credentials against the
- associated properties in <filename>guacamole.properties</filename> (our source of
- authentication information for the sake of this tutorial).</para>
- <para>We will define four properties:<variablelist>
- <varlistentry>
- <term><property>tutorial-user</property></term>
- <listitem>
- <para>The name of the only user we accept.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>tutorial-password</property></term>
- <listitem>
- <para>The password we require for the user specified to be
- authenticated.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>tutorial-protocol</property></term>
- <listitem>
- <para>The protocol of the configuration this user is authorized to use,
- which will be sent to guacd when the user logs in and selects their
- connection.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>tutorial-parameters</property></term>
- <listitem>
- <para>A comma-delimited list of
- <code><replaceable>name</replaceable>=<replaceable>value</replaceable></code>
- pairs. For the sake of simplicity, we'll assume there will never be any
- commas in the values.</para>
- </listitem>
- </varlistentry>
- </variablelist></para>
- <para>If the username and password match what is stored in the file, we read the
- configuration information, store it in a <classname>GuacamoleConfiguration</classname>,
- and return the configuration within a set, telling Guacamole that this user is
- authorized but only to access the configurations returned.</para>
- <para>Upstream, we always place the properties of authentication providers in their own
- class, and so we will also do that here in this tutorial, as it keeps things
- organized.</para>
- <example>
- <title><filename>TutorialProperties.java</filename>, a class containing property
- definitions</title>
- <programlisting>package org.apache.guacamole.auth;
-
-import org.apache.guacamole.properties.StringGuacamoleProperty;
-
-/**
- * Utility class containing all properties used by the custom authentication
- * tutorial. The properties defined here must be specified within
- * guacamole.properties to configure the tutorial authentication provider.
- */
-public class TutorialGuacamoleProperties {
-
- /**
- * This class should not be instantiated.
- */
- private TutorialGuacamoleProperties() {}
-
- /**
- * The only user to allow.
- */
- public static final StringGuacamoleProperty TUTORIAL_USER =
- new StringGuacamoleProperty() {
-
- @Override
- public String getName() { return "tutorial-user"; }
-
- };
-
- /**
- * The password required for the specified user.
- */
- public static final StringGuacamoleProperty TUTORIAL_PASSWORD =
- new StringGuacamoleProperty() {
-
- @Override
- public String getName() { return "tutorial-password"; }
-
- };
-
-
- /**
- * The protocol to use when connecting.
- */
- public static final StringGuacamoleProperty TUTORIAL_PROTOCOL =
- new StringGuacamoleProperty() {
-
- @Override
- public String getName() { return "tutorial-protocol"; }
-
- };
-
-
- /**
- * All parameters associated with the connection, as a comma-delimited
- * list of name="value"
- */
- public static final StringGuacamoleProperty TUTORIAL_PARAMETERS =
- new StringGuacamoleProperty() {
-
- @Override
- public String getName() { return "tutorial-parameters"; }
-
- };
-
-}</programlisting>
- </example>
- <para>Normally, we would define a new type of <classname>GuacamoleProperty</classname> to
- handle the parsing of the parameters required by <varname>TUTORIAL_PARAMETERS</varname>,
- but for the sake of simplicity, parsing of this parameter will be embedded in the
- authentication function later.</para>
- <para>You will need to modify your existing <filename>guacamole.properties</filename> file,
- adding each of the above properties to describe one of your available
- connections.</para>
- <example>
- <title>Properties describing a user and connection, as required by this tutorial</title>
- <programlisting># Username and password
-tutorial-user: <replaceable>tutorial</replaceable>
-tutorial-password: <replaceable>password</replaceable>
-
-# Connection information
-tutorial-protocol: <replaceable>vnc</replaceable>
-tutorial-parameters: <replaceable>hostname=localhost, port=5900</replaceable></programlisting>
- </example>
- <para>Once these properties and their accessor class are in place, it's simple enough to
- read the properties within <methodname>getAuthorizedConfigurations()</methodname> and
- authenticate the user based on their username and password.</para>
- <example>
- <title>Checking the credentials against the properties</title>
- <programlisting>@Override
-public Map<String, GuacamoleConfiguration>
- getAuthorizedConfigurations(Credentials credentials)
- throws GuacamoleException {
-
- // Get the Guacamole server environment
- Environment environment = new LocalEnvironment();
-
- // Get username from guacamole.properties
- String username = environment.getRequiredProperty(
- TutorialGuacamoleProperties.TUTORIAL_USER
- );
-
- // If wrong username, fail
- if (!username.equals(credentials.getUsername()))
- return null;
-
- // Get password from guacamole.properties
- String password = environment.getRequiredProperty(
- TutorialGuacamoleProperties.TUTORIAL_PASSWORD
- );
-
- // If wrong password, fail
- if (!password.equals(credentials.getPassword()))
- return null;
-
- // Successful login. Return configurations (STUB)
- return new HashMap<String, GuacamoleConfiguration>();
-
-}</programlisting>
- </example>
- <para>As is, the authentication provider will work in its current state in that the correct
- username and password will authenticate the user, while an incorrect username or
- password will not, but we still aren't returning an actual map of configurations. We
- need to construct the configuration based on the properties in the
- <filename>guacamole.properties</filename> file after the user has been
- authenticated, and return that configuration to the web application.</para>
- </section>
- <section xml:id="custom-auth-more-config">
- <title>Parsing the configuration</title>
- <para>The only remaining task before we have a fully-functioning authentication provider is
- to actually parse the configuration from the <filename>guacamole.properties</filename>
- file.</para>
- <example>
- <title>Parsing and returning a <classname>GuacamoleConfiguration</classname></title>
- <programlisting>@Override
-public Map<String, GuacamoleConfiguration>
- getAuthorizedConfigurations(Credentials credentials)
- throws GuacamoleException {
-
- // Get the Guacamole server environment
- Environment environment = new LocalEnvironment();
-
- // Get username from guacamole.properties
- String username = environment.getRequiredProperty(
- TutorialGuacamoleProperties.TUTORIAL_USER
- );
-
- // If wrong username, fail
- if (!username.equals(credentials.getUsername()))
- return null;
-
- // Get password from guacamole.properties
- String password = environment.getRequiredProperty(
- TutorialGuacamoleProperties.TUTORIAL_PASSWORD
- );
-
- // If wrong password, fail
- if (!password.equals(credentials.getPassword()))
- return null;
-
- // Successful login. Return configurations.
- Map<String, GuacamoleConfiguration> configs =
- new HashMap<String, GuacamoleConfiguration>();
-
- // Create new configuration
- GuacamoleConfiguration config = new GuacamoleConfiguration();
-
- // Set protocol specified in properties
- config.setProtocol(environment.getRequiredProperty(
- TutorialGuacamoleProperties.TUTORIAL_PROTOCOL
- ));
-
- // Set all parameters, splitting at commas
- for (String parameterValue : environment.getRequiredProperty(
- TutorialGuacamoleProperties.TUTORIAL_PARAMETERS
- ).split(",\\s*")) {
-
- // Find the equals sign
- int equals = parameterValue.indexOf('=');
- if (equals == -1)
- throw new GuacamoleServerException("Required equals sign missing");
-
- // Get name and value from parameter string
- String name = parameterValue.substring(0, equals);
- String value = parameterValue.substring(equals+1);
-
- // Set parameter as specified
- config.setParameter(name, value);
-
- }
-
- configs.put("Tutorial Connection", config);
- return configs;
-
-}</programlisting>
- </example>
- <para>The extension is now complete and can be built as described earlier in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="custom-auth-building"/>.</para>
- </section>
- <section xml:id="custom-auth-installing">
- <title>Installing the extension</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- installed by being placed within <filename>GUACAMOLE_HOME/extensions</filename>, and
- this extension is no different. As described in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="configuring-guacamole"/>,
- <varname>GUACAMOLE_HOME</varname> is a placeholder used to refer to the directory
- that Guacamole uses to locate its configuration files and extensions. Typically, this
- will be the <filename>.guacamole</filename> directory within the home directory of the
- user running Tomcat.</para>
- <para>To install your extension, ensure that the required properties have been added to your
- <filename>guacamole.properties</filename>, copy the
- <filename>target/guacamole-auth-tutorial-1.3.0.jar</filename> file into
- <filename>GUACAMOLE_HOME/extensions</filename> and restart Tomcat. Guacamole will
- automatically load your extension, logging an informative message that it has done
- so:</para>
- <informalexample>
- <screen>Extension "Tutorial Authentication Extension" loaded.</screen>
- </informalexample>
- </section>
-</chapter>
diff --git a/src/chapters/docker.xml b/src/chapters/docker.xml
deleted file mode 100644
index a0a1006..0000000
--- a/src/chapters/docker.xml
+++ /dev/null
@@ -1,1013 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="guacamole-docker" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xl="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Installing Guacamole with Docker</title>
- <indexterm>
- <primary>docker</primary>
- </indexterm>
- <para>Guacamole can be deployed using Docker, removing the need to build
- <package>guacamole-server</package> from source or configure the web application
- manually. The Guacamole project provides officially-supported Docker images for both
- Guacamole and <package>guacd</package> which are kept up-to-date with each release.</para>
- <para>A typical Docker deployment of Guacamole will involve three separate containers, linked
- together at creation time:</para>
- <variablelist>
- <varlistentry>
- <term><systemitem>guacamole/guacd</systemitem></term>
- <listitem>
- <para>Provides the <package>guacd</package> daemon, built from the released
- <package>guacamole-server</package> source with support for VNC, RDP, SSH,
- telnet, and Kubernetes.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><systemitem>guacamole/guacamole</systemitem></term>
- <listitem>
- <para>Provides the Guacamole web application running within Tomcat 8 with support
- for WebSocket. The configuration necessary to connect to
- <package>guacd</package>, MySQL, PostgreSQL, LDAP, etc. will be generated
- automatically when the image starts based on Docker links or environment
- variables.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <variablelist>
- <varlistentry>
- <term><systemitem>mysql</systemitem> or <systemitem>postgresql</systemitem></term>
- <listitem>
- <para>Provides the database that Guacamole will use for authentication and storage
- of connection configuration data.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>This separation is important, as it facilitates upgrades and maintains proper separation
- of concerns. With the database separate from Guacamole and <package>guacd</package>, those
- containers can be freely destroyed and recreated at will. The only container which must
- persist data through upgrades is the database.</para>
- <section xml:id="guacd-docker-image">
- <title>Running the <package>guacd</package> Docker image</title>
- <para>The <package>guacd</package> Docker image is built from the released
- <package>guacamole-server</package> source with support for VNC, RDP, SSH, telnet,
- and Kubernetes. Common pitfalls like installing the required dependencies, installing
- fonts for SSH, telnet, or Kubernetes, and ensuring the FreeRDP plugins are installed to
- the correct location are all taken care of. It will simply just work.</para>
- <section xml:id="guacd-docker-guacamole">
- <title>Running <package>guacd</package> for use by the Guacamole Docker image</title>
- <para>When running the <package>guacd</package> image with the intent of linking to a
- Guacamole container, no ports need be exposed on the network. Access to these ports
- will be handled automatically by Docker during linking, and the Guacamole image will
- properly detect and configure the connection to <package>guacd</package>.</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacd</replaceable> -d guacamole/guacd</screen>
- </informalexample>
- <para>When run in this manner, <package>guacd</package> will be listening on its default
- port 4822, but this port will only be available to Docker containers that have been
- explicitly linked to
- <varname><replaceable>some-guacd</replaceable></varname>.</para>
- <para>The log level of guacd can be controlled with the <varname>GUACD_LOG_LEVEL</varname> environment variable. The
- default value is <varname><replaceable>info</replaceable></varname>, and can be set to any of the
- valid settings for the guacd log flag (-L).</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run -e GUACD_LOG_LEVEL=<replaceable>debug</replaceable> -d guacamole/guacd</screen>
- </informalexample>
- </section>
- <section xml:id="guacd-docker-external">
- <title>Running <package>guacd</package> for use by services outside Docker</title>
- <para>If you are not going to use the Guacamole image, you can still leverage the
- <package>guacd</package> image for ease of installation and maintenance. By
- exposing the <package>guacd</package> port, 4822, services external to Docker will
- be able to access <package>guacd</package>.</para>
- <important>
- <para><emphasis>Take great care when doing this</emphasis> -
- <package>guacd</package> is a passive proxy and does not perform any kind of
- authentication.</para>
- <para>If you do not properly isolate <package>guacd</package> from untrusted parts
- of your network, malicious users may be able to use <package>guacd</package> as
- a jumping point to other systems.</para>
- </important>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacd</replaceable> -d -p 4822:4822 guacamole/guacd</screen>
- </informalexample>
- <para><package>guacd</package> will now be listening on port 4822, and Docker will
- expose this port on the same server hosting Docker. Other services, such as an
- instance of Tomcat running outside of Docker, will be able to connect to
- <package>guacd</package> directly.</para>
- </section>
- </section>
- <section xml:id="guacamole-docker-image">
- <title>The Guacamole Docker image</title>
- <para>The Guacamole Docker image is built on top of a standard Tomcat 8 image and takes care
- of all configuration automatically. The configuration information required for
- <package>guacd</package> and the various authentication mechanisms are specified
- with environment variables or Docker links given when the container is created.</para>
- <important>
- <para>If using <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-docker-postgresql">PostgreSQL</link> or <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="guacamole-docker-mysql"
- >MySQL</link> for authentication, <emphasis>you will need to initialize the
- database manually</emphasis>. Guacamole will not automatically create its own
- tables, but SQL scripts are provided to do this.</para>
- </important>
- <para>Once the Guacamole image is running, Guacamole will be accessible at
- <uri>http://<replaceable>HOSTNAME</replaceable>:8080/guacamole/</uri>, where
- <replaceable>HOSTNAME</replaceable> is the hostname or address of the machine
- hosting Docker.</para>
- <section xml:id="guacamole-docker-config-via-env">
- <title>Configuring Guacamole when using Docker</title>
- <para>When running Guacamole using Docker, the traditional approach to configuring
- Guacamole by editing <filename>guacamole.properties</filename> is less
- convenient. When using Docker, you may wish to make use of the
- <parameter>enable-environment-properties</parameter> configuration
- property, which allows you to specify values for arbitrary Guacamole
- configuration properties using environment variables. This is covered in
- <xref xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="configuring-guacamole"/>.
- </para>
- </section>
- <section xml:id="guacamole-docker-guacd">
- <title>Connecting Guacamole to <package>guacd</package></title>
- <para>The Guacamole Docker image needs to be able to connect to <package>guacd</package>
- to establish remote desktop connections, just like any other Guacamole deployment.
- The connection information needed by Guacamole will be provided either via a Docker
- link or through environment variables.</para>
- <para>If you will be using Docker to provide <package>guacd</package>, and you wish to
- use a Docker link to connect the Guacamole image to <package>guacd</package>, the
- connection details are implied by the Docker link:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacamole</replaceable> \
- <emphasis>--link <replaceable>some-guacd</replaceable>:guacd</emphasis> \
- ...
- -d -p 8080:8080 guacamole/guacamole</screen>
- <para>If you are not using Docker to provide <package>guacd</package>, you will need
- to provide the network connection information yourself using additional
- environment variables:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="4*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>GUACD_HOSTNAME</envar></entry>
- <entry>
- <para>The hostname of the <package>guacd</package> instance to
- use to establish remote desktop connections. <emphasis>This
- is required if you are not using Docker to provide
- <package>guacd</package>.</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>GUACD_PORT</envar></entry>
- <entry>
- <para>The port that Guacamole should use when connecting to
- <package>guacd</package>. This environment variable is
- optional. If not provided, the standard
- <package>guacd</package> port of 4822 will be
- used.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>The <envar>GUACD_HOSTNAME</envar> and, if necessary, <envar>GUACD_PORT</envar>
- environment variables can thus be used in place of a Docker link if using a
- Docker link is impossible or undesirable:</para>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacamole</replaceable> \
- <emphasis>-e GUACD_HOSTNAME=<replaceable>172.17.42.1</replaceable> \
- -e GUACD_PORT=<replaceable>4822</replaceable></emphasis> \
- ...
- -d -p 8080:8080 guacamole/guacamole</screen>
- </informalexample>
- <para><emphasis>A connection to <package>guacd</package> is not the only thing required
- for Guacamole to work</emphasis>; some authentication mechanism needs to be
- configured, as well. <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-docker-mysql">MySQL</link>, <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="guacamole-docker-postgresql"
- >PostgreSQL</link>, and <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-docker-ldap">LDAP</link> are supported for this, and are
- described in more detail in the sections below. If the required configuration
- options for at least one authentication mechanism are not provided, the Guacamole
- image will not be able to start up, and you will see an error.</para>
- </section>
- <section xml:id="guacamole-docker-mysql">
- <title>MySQL authentication</title>
- <para>To use Guacamole with the MySQL authentication backend, you will need either a
- Docker container running the <systemitem>mysql</systemitem> image, or network access
- to a working installation of MySQL. The connection to MySQL can be specified using
- either environment variables or a Docker link.</para>
- <section xml:id="initializing-guacamole-docker-mysql">
- <title>Initializing the MySQL database</title>
- <para>If your database is not already initialized with the Guacamole schema, you
- will need to do so prior to using Guacamole. A convenience script for generating
- the necessary SQL to do this is included in the Guacamole image.</para>
- <para>To generate a SQL script which can be used to initialize a fresh MySQL
- database as documented in <xref linkend="jdbc-auth"/>:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > <replaceable>initdb.sql</replaceable></screen>
- </informalexample>
- <para>Alternatively, you can use the SQL scripts included with the database
- authentication.</para>
- <para>Once this script is generated, you must:</para>
- <procedure>
- <step>
- <para>Create a database for Guacamole within MySQL, such as
- <database><replaceable>guacamole_db</replaceable></database>.</para>
- </step>
- <step>
- <para>Create a user for Guacamole within MySQL with access to this database,
- such as
- <systemitem><replaceable>guacamole_user</replaceable></systemitem>.</para>
- </step>
- <step>
- <para>Run the script on the newly-created database.</para>
- </step>
- </procedure>
- <para>The process for doing this via the <command>mysql</command> utility included
- with MySQL is documented in <xref linkend="jdbc-auth"/>.</para>
- </section>
- <section xml:id="guacamole-docker-mysql-connecting">
- <title>Connecting Guacamole to MySQL</title>
- <para>If your MySQL database is provided by another Docker container, and you wish
- to use a Docker link to connect the Guacamole image to your database, the
- connection details are implied by the Docker link itself:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacamole</replaceable> \
- --link some-guacd:guacd \
- <emphasis>--link <replaceable>some-mysql</replaceable>:mysql</emphasis> \
- ...
- -d -p 8080:8080 guacamole/guacamole</screen>
- </informalexample>
- <para>If you are not using Docker to provide your MySQL database, you will need to
- provide the network connection information yourself using additional environment
- variables:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="4*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>MYSQL_HOSTNAME</envar></entry>
- <entry>
- <para>The hostname of the database to use for Guacamole
- authentication. <emphasis>This is required if you are not
- using Docker to provide your MySQL
- database.</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>MYSQL_PORT</envar></entry>
- <entry>
- <para>The port that Guacamole should use when connecting to
- MySQL. This environment variable is optional. If not
- provided, the standard MySQL port of 3306 will be
- used.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>The <envar>MYSQL_HOSTNAME</envar> and, if necessary, <envar>MYSQL_PORT</envar>
- environment variables can thus be used in place of a Docker link if using a
- Docker link is impossible or undesirable:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacamole</replaceable> \
- --link some-guacd:guacd \
- <emphasis>-e MYSQL_HOSTNAME=<replaceable>172.17.42.1</replaceable> \</emphasis>
- ...
- -d -p 8080:8080 guacamole/guacamole</screen>
- </informalexample>
- <para>Note that a Docker link to <package>guacd</package> (the <option>--link
- some-guacd:guacd</option> option above) is not required any more than a
- Docker link is required for MySQL. The connection information for
- <package>guacd</package> can be specified using environment variables, as
- described in <xref xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-docker-guacd"/>.</para>
- </section>
- <section xml:id="guacamole-docker-mysql-required-vars">
- <title xml:id="deploying-guacamole-docker-mysql">Required environment
- variables</title>
- <para>Using MySQL for authentication requires additional configuration parameters
- specified via environment variables. These variables collectively describe how
- Guacamole will connect to MySQL:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="4*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>MYSQL_DATABASE</envar></entry>
- <entry>
- <para>The name of the database to use for Guacamole
- authentication.</para>
- </entry>
- </row>
- <row>
- <entry><envar>MYSQL_USER</envar></entry>
- <entry>
- <para>The user that Guacamole will use to connect to
- MySQL.</para>
- </entry>
- </row>
- <row>
- <entry><envar>MYSQL_PASSWORD</envar></entry>
- <entry>
- <para>The password that Guacamole will provide when connecting
- to MySQL as <envar>MYSQL_USER</envar>.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>If any required environment variables are omitted, you will receive an error
- message in the logs, and the image will stop. You will then need to recreate the
- container with the proper variables specified.</para>
- </section>
- <section xml:id="guacamole-docker-mysql-optional-vars">
- <title>Optional environment variables</title>
- <para>Additional optional environment variables may be used to override Guacamole's
- default behavior with respect to concurrent connection use by one or more users.
- Concurrent use of connections and connection groups can be limited to an overall
- maximum and/or a per-user maximum:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="1.15*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>MYSQL_ABSOLUTE_MAX_CONNECTIONS</envar></entry>
- <entry>
- <para>The absolute maximum number of concurrent connections to
- allow at any time, regardless of the Guacamole connection or
- user involved. If set to "0", this will be unlimited.
- Because this limit applies across all Guacamole connections,
- it cannot be overridden if set.</para>
- <para><emphasis>By default, the absolute total number of
- concurrent connections is unlimited
- ("0").</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>MYSQL_DEFAULT_MAX_CONNECTIONS</envar></entry>
- <entry>
- <para>The maximum number of concurrent connections to allow to
- any one Guacamole connection. If set to "0", this will be
- unlimited. This can be overridden on a per-connection basis
- when editing a connection.</para>
- <para><emphasis>By default, overall concurrent use of
- connections is unlimited ("0").</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS</envar></entry>
- <entry>
- <para>The maximum number of concurrent connections to allow to
- any one Guacamole connection group. If set to "0", this will
- be unlimited. This can be overridden on a per-group basis
- when editing a connection group.</para>
- <para><emphasis>By default, overall concurrent use of connection
- groups is unlimited ("0").</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER</envar></entry>
- <entry>
- <para>The maximum number of concurrent connections to allow a
- single user to maintain to any one Guacamole connection. If
- set to "0", this will be unlimited. This can be overridden
- on a per-connection basis when editing a connection.</para>
- <para><emphasis>By default, per-user concurrent use of
- connections is unlimited ("0").</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER</envar></entry>
- <entry>
- <para>The maximum number of concurrent connections to allow a
- single user to maintain to any one Guacamole connection
- group. If set to "0", this will be unlimited. This can be
- overridden on a per-group basis when editing a connection
- group.</para>
- <para><emphasis>By default, per-user concurrent use of
- connection groups is limited to one ("1")</emphasis>, to
- prevent a balancing connection group from being completely
- exhausted by one user alone.</para>
- </entry>
- </row>
- <row>
- <entry><envar>MYSQL_AUTO_CREATE_ACCOUNTS</envar></entry>
- <entry>
- <para>Whether or not accounts that do not exist in the
- MySQL database will be automatically created when successfully
- authenticated through other modules. If set to "true" accounts
- will be automatically created. Otherwise, and by default,
- accounts will not be automatically created and will need to
- be manually created in order for permissions within the
- MySQL database extension to be assigned to users
- authenticated with other modules.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- </section>
- <section xml:id="guacamole-docker-postgresql">
- <title>PostgreSQL authentication</title>
- <para>To use Guacamole with the PostgreSQL authentication backend, you will need either
- a Docker container running the <systemitem>postgres</systemitem> image, or network
- access to a working installation of PostgreSQL. The connection to PostgreSQL can be
- specified using either environment variables or a Docker link.</para>
- <section xml:id="initializing-guacamole-docker-postgresql">
- <title>Initializing the PostgreSQL database</title>
- <para>If your database is not already initialized with the Guacamole schema, you
- will need to do so prior to using Guacamole. A convenience script for generating
- the necessary SQL to do this is included in the Guacamole image.</para>
- <para>To generate a SQL script which can be used to initialize a fresh PostgreSQL
- database as documented in <xref linkend="jdbc-auth"/>:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --postgres > <replaceable>initdb.sql</replaceable></screen>
- </informalexample>
- <para>Alternatively, you can use the SQL scripts included with the database
- authentication.</para>
- <para>Once this script is generated, you must:</para>
- <procedure>
- <step>
- <para>Create a database for Guacamole within PostgreSQL, such as
- <database><replaceable>guacamole_db</replaceable></database>.</para>
- </step>
- <step>
- <para>Run the script on the newly-created database.</para>
- </step>
- <step>
- <para>Create a user for Guacamole within PostgreSQL with access to the
- tables and sequences of this database, such as
- <systemitem><replaceable>guacamole_user</replaceable></systemitem>.</para>
- </step>
- </procedure>
- <para>The process for doing this via the <command>psql</command> and
- <command>createdb</command> utilities included with PostgreSQL is documented
- in <xref linkend="jdbc-auth"/>.</para>
- </section>
- <section xml:id="guacamole-docker-postgresql-connecting">
- <title>Connecting Guacamole to PostgreSQL</title>
- <para>If your PostgreSQL database is provided by another Docker container, and you
- wish to use a Docker link to connect the Guacamole image to your database, the
- connection details are implied by the Docker link itself:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacamole</replaceable> \
- --link some-guacd:guacd \
- <emphasis>--link <replaceable>some-postgres</replaceable>:postgres</emphasis> \
- ...
- -d -p 8080:8080 guacamole/guacamole</screen>
- </informalexample>
- <para>If you are not using Docker to provide your PostgreSQL database, you will need
- to provide the network connection information yourself using additional
- environment variables:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="4*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>POSTGRES_HOSTNAME</envar></entry>
- <entry>
- <para>The hostname of the database to use for Guacamole
- authentication. <emphasis>This is required if you are not
- using Docker to provide your PostgreSQL
- database.</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>POSTGRES_PORT</envar></entry>
- <entry>
- <para>The port that Guacamole should use when connecting to
- PostgreSQL. This environment variable is optional. If not
- provided, the standard PostgreSQL port of 5432 will be
- used.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>The <envar>POSTGRES_HOSTNAME</envar> and, if necessary,
- <envar>POSTGRES_PORT</envar> environment variables can thus be used in place
- of a Docker link if using a Docker link is impossible or undesirable:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacamole</replaceable> \
- --link some-guacd:guacd \
- <emphasis>-e POSTGRES_HOSTNAME=<replaceable>172.17.42.1</replaceable> \</emphasis>
- ...
- -d -p 8080:8080 guacamole/guacamole</screen>
- </informalexample>
- <para>Note that a Docker link to <package>guacd</package> (the <option>--link
- some-guacd:guacd</option> option above) is not required any more than a
- Docker link is required for PostgreSQL. The connection information for
- <package>guacd</package> can be specified using environment variables, as
- described in <xref xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-docker-guacd"/>.</para>
- </section>
- <section xml:id="guacamole-docker-postgresql-required-vars">
- <title>Required environment variables</title>
- <para>Using PostgreSQL for authentication requires additional configuration
- parameters specified via environment variables. These variables collectively
- describe how Guacamole will connect to PostgreSQL:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="4*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>POSTGRES_DATABASE</envar></entry>
- <entry>
- <para>The name of the database to use for Guacamole
- authentication.</para>
- </entry>
- </row>
- <row>
- <entry><envar>POSTGRES_USER</envar></entry>
- <entry>
- <para>The user that Guacamole will use to connect to
- PostgreSQL.</para>
- </entry>
- </row>
- <row>
- <entry><envar>POSTGRES_PASSWORD</envar></entry>
- <entry>
- <para>The password that Guacamole will provide when connecting
- to PostgreSQL as <envar>POSTGRES_USER</envar>.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>If any required environment variables are omitted, you will receive an error
- message in the logs, and the image will stop. You will then need to recreate the
- container with the proper variables specified.</para>
- </section>
- <section xml:id="guacamole-docker-postgresql-optional-vars">
- <title>Optional environment variables</title>
- <para>Additional optional environment variables may be used to override Guacamole's
- default behavior with respect to concurrent connection use by one or more users.
- Concurrent use of connections and connection groups can be limited to an overall
- maximum and/or a per-user maximum:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="1.15*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>POSTGRES_ABSOLUTE_MAX_CONNECTIONS</envar></entry>
- <entry>
- <para>The absolute maximum number of concurrent connections to
- allow at any time, regardless of the Guacamole connection or
- user involved. If set to "0", this will be unlimited.
- Because this limit applies across all Guacamole connections,
- it cannot be overridden if set.</para>
- <para><emphasis>By default, the absolute total number of
- concurrent connections is unlimited
- ("0").</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>POSTGRES_DEFAULT_MAX_CONNECTIONS</envar></entry>
- <entry>
- <para>The maximum number of concurrent connections to allow to
- any one Guacamole connection. If set to "0", this will be
- unlimited. This can be overridden on a per-connection basis
- when editing a connection.</para>
- <para><emphasis>By default, overall concurrent use of
- connections is unlimited ("0").</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>POSTGRES_DEFAULT_MAX_GROUP_CONNECTIONS</envar></entry>
- <entry>
- <para>The maximum number of concurrent connections to allow to
- any one Guacamole connection group. If set to "0", this will
- be unlimited. This can be overridden on a per-group basis
- when editing a connection group.</para>
- <para><emphasis>By default, overall concurrent use of connection
- groups is unlimited ("0").</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>POSTGRES_DEFAULT_MAX_CONNECTIONS_PER_USER</envar></entry>
- <entry>
- <para>The maximum number of concurrent connections to allow a
- single user to maintain to any one Guacamole connection. If
- set to "0", this will be unlimited. This can be overridden
- on a per-connection basis when editing a connection.</para>
- <para><emphasis>By default, per-user concurrent use of
- connections is unlimited ("0").</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>POSTGRES_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER</envar></entry>
- <entry>
- <para>The maximum number of concurrent connections to allow a
- single user to maintain to any one Guacamole connection
- group. If set to "0", this will be unlimited. This can be
- overridden on a per-group basis when editing a connection
- group.</para>
- <para><emphasis>By default, per-user concurrent use of
- connection groups is limited to one ("1")</emphasis>, to
- prevent a balancing connection group from being completely
- exhausted by one user alone.</para>
- </entry>
- </row>
- <row>
- <entry><envar>POSTGRES_AUTO_CREATE_ACCOUNTS</envar></entry>
- <entry>
- <para>Whether or not accounts that do not exist in the
- PostgreSQL database will be automatically created when
- successfully authenticated through other modules. If set
- to "true", accounts will be automatically created. Otherwise,
- and by default, accounts will not be automatically created
- and will need to be manually created in order for permissions
- within the PostgreSQL database extension to be assigned to
- users authenticated with other modules.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>Optional environment variables may also be used to override Guacamole's
- default behavior with respect to timeouts at the database and network level:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="1.15*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>POSTGRES_DEFAULT_STATEMENT_TIMEOUT</envar></entry>
- <entry>
- <para>The number of seconds the driver will wait for a
- response from the database, before aborting the query.
- A value of 0 (the default) means the timeout is disabled.</para>
- </entry>
- </row>
- <row>
- <entry><envar>POSTGRES_SOCKET_TIMEOUT</envar></entry>
- <entry>
- <para>The number of seconds to wait for socket read
- operations. If reading from the server takes longer than
- this value, the connection will be closed. This can be used
- to handle network problems such as a dropped connection to
- the database. Similar to
- <envar>POSTGRES_DEFAULT_STATEMENT_TIMEOUT</envar>,
- it will also abort queries that take too long. A value of 0
- (the default) means the timeout is disabled.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
-
- </section>
- </section>
- <section xml:id="guacamole-docker-ldap">
- <title>LDAP authentication</title>
- <para>To use Guacamole with the LDAP authentication backend, you will need network
- access to an LDAP directory. Unlike MySQL and PostgreSQL, the Guacamole Docker image
- does not support Docker links for LDAP; the connection information
- <emphasis>must</emphasis> be specified using environment variables:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.5*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>LDAP_HOSTNAME</envar></entry>
- <entry>
- <para>The hostname or IP address of your LDAP server.</para>
- </entry>
- </row>
- <row>
- <entry><envar>LDAP_PORT</envar></entry>
- <entry>
- <para>The port your LDAP server listens on. By default, this will be
- 389 for unencrypted LDAP or LDAP using STARTTLS, and 636 for
- LDAP over SSL (LDAPS).</para>
- </entry>
- </row>
- <row>
- <entry><envar>LDAP_ENCRYPTION_METHOD</envar></entry>
- <entry>
- <para>The encryption mechanism that Guacamole should use when
- communicating with your LDAP server. Legal values are "none" for
- unencrypted LDAP, "ssl" for LDAP over SSL/TLS (commonly known as
- LDAPS), or "starttls" for STARTTLS. If omitted, encryption will
- not be used.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>Only the <envar>LDAP_HOSTNAME</envar> variable is required, but you may also need
- to specify <envar>LDAP_PORT</envar> or <envar>LDAP_ENCRYPTION_METHOD</envar> if your
- LDAP directory uses encryption or listens on a non-standard port:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacamole</replaceable> \
- --link some-guacd:guacd \
- <emphasis>-e LDAP_HOSTNAME=<replaceable>172.17.42.1</replaceable> \</emphasis>
- ...
- -d -p 8080:8080 guacamole/guacamole</screen>
- </informalexample>
- <para>Note that a Docker link to <package>guacd</package> (the <option>--link
- some-guacd:guacd</option> option above) is not required. Similar to LDAP, the
- connection information for <package>guacd</package> can be specified using
- environment variables, as described in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="guacamole-docker-guacd"
- />.</para>
- <section xml:id="guacamole-docker-ldap-required-vars">
- <title>Required environment variables</title>
- <para>Using LDAP for authentication requires additional configuration parameters
- specified via environment variables. These variables collectively describe how
- Guacamole will query your LDAP directory:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="4*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>LDAP_USER_BASE_DN</envar></entry>
- <entry>
- <para>The base of the DN for all Guacamole users. All Guacamole
- users that will be authenticating against LDAP must be
- descendents of this base DN.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>As with the other authentication mechanisms, if any required environment
- variables are omitted (including those required for connecting to the LDAP
- directory over the network), you will receive an error message in the logs, and
- the image will stop. You will then need to recreate the container with the
- proper variables specified.</para>
- </section>
- <section xml:id="guacamole-docker-ldap-optional-vars">
- <title>Optional environment variables</title>
- <para>Additional optional environment variables may be used to configure the details
- of your LDAP directory hierarchy, or to enable more flexible searching for user
- accounts:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="2.25*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>LDAP_GROUP_BASE_DN</envar></entry>
- <entry>
- <para>The base of the DN for all groups that may be referenced
- within Guacamole configurations using the standard
- <property>seeAlso</property> attribute. All groups which
- will be used to control access to Guacamole configurations
- must be descendents of this base DN. <emphasis>If this
- variable is omitted, the <property>seeAlso</property>
- attribute will have no effect on Guacamole
- configurations.</emphasis></para>
- </entry>
- </row>
- <row>
- <entry><envar>LDAP_SEARCH_BIND_DN</envar></entry>
- <entry>
- <para>The DN (Distinguished Name) of the user to bind as when
- authenticating users that are attempting to log in. If
- specified, Guacamole will query the LDAP directory to
- determine the DN of each user that logs in. If omitted, each
- user's DN will be derived directly using the base DN
- specified with <envar>LDAP_USER_BASE_DN</envar>.</para>
- </entry>
- </row>
- <row>
- <entry><envar>LDAP_SEARCH_BIND_PASSWORD</envar></entry>
- <entry>
- <para>The password to provide to the LDAP server when binding as
- <envar>LDAP_SEARCH_BIND_DN</envar> to authenticate other
- users. This variable is only used if
- <envar>LDAP_SEARCH_BIND_DN</envar> is specified. If
- omitted, but <envar>LDAP_SEARCH_BIND_DN</envar> is
- specified, Guacamole will attempt to bind with the LDAP
- server without a password.</para>
- </entry>
- </row>
- <row>
- <entry><envar>LDAP_USERNAME_ATTRIBUTE</envar></entry>
- <entry>
- <para>The attribute or attributes which contain the username
- within all Guacamole user objects in the LDAP directory.
- Usually, and by default, this will simply be
- "<property>uid</property>". If your LDAP directory
- contains users whose usernames are dictated by different
- attributes, multiple attributes can be specified here,
- separated by commas, but beware: <emphasis>doing so requires
- that a search DN be provided with
- <envar>LDAP_SEARCH_BIND_DN</envar></emphasis>.</para>
- </entry>
- </row>
- <row>
- <entry><envar>LDAP_CONFIG_BASE_DN</envar></entry>
- <entry>
- <para>The base of the DN for all Guacamole configurations. If
- omitted, the configurations of Guacamole connections will
- simply not be queried from the LDAP directory, and you will
- need to store them elsewhere, such as within a MySQL or
- PostgreSQL database.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>As documented in <xref xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="ldap-auth"/>, Guacamole does support combining LDAP with a MySQL or
- PostgreSQL database, and this can be configured with the Guacamole Docker image,
- as well. Each of these authentication mechanisms is independently configurable
- using their respective environment variables, and by providing the required
- environment variables for multiple systems, Guacamole will automatically be
- configured to use each when the Docker image starts.</para>
- </section>
- </section>
- <section xml:id="guacamole-docker-header-auth">
- <title>Header Authentication</title>
- <para>The header authentication extension can be used to authenticate Guacamole
- through a trusted third-party server, where the authenticated user's username
- is passed back to Guacamole via a specific HTTP header. The following
- are valid Docker variables for enabling and configuring header
- authentication:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="2.25*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>HEADER_ENABLED</envar></entry>
- <entry>
- <para>Enables authentication via the header extension,
- which causes the extension to be loaded when
- Guacamole starts. By default this is false and the
- header extension will not be loaded.</para>
- </entry>
- </row>
- <row>
- <entry><envar>HTTP_AUTH_HEADER</envar></entry>
- <entry>
- <para>Optional environment variable that, if set,
- configures the name of the HTTP header that will
- be used used to authenticate the user to
- Guacamole. If this is not specified the default
- value of REMOTE_USER will be used.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="guacamole-docker-guacamole-home">
- <title>Custom extensions and <envar>GUACAMOLE_HOME</envar></title>
- <para>If you have your own or third-party extensions for Guacamole which are not
- supported by the Guacamole Docker image, but are compatible with the version of
- Guacamole within the image, you can still use them by providing a custom base
- configuration using the <envar>GUACAMOLE_HOME</envar> environment variable:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="4*"/>
- <thead>
- <row>
- <entry>Variable</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><envar>GUACAMOLE_HOME</envar></entry>
- <entry>
- <para>The absolute path to the directory within the Docker container
- to use <emphasis>as a template</emphasis> for the image's
- automatically-generated <link
- xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-home"
- ><envar>GUACAMOLE_HOME</envar></link>. Any configuration
- generated by the Guacamole Docker image based on other
- environment variables will be applied to an independent copy of
- the contents of this directory.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>You will <emphasis>still</emphasis> need to follow the steps required to create
- the contents of <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-home"><envar>GUACAMOLE_HOME</envar></link> specific to your
- extension (placing the extension itself within
- <filename><replaceable>GUACAMOLE_HOME</replaceable>/extensions/</filename>,
- adding any properties to <filename>guacamole.properties</filename>, etc.), but the
- rest of Guacamole's configuration will be handled automatically, overlaid on top of
- a copy of the <envar>GUACAMOLE_HOME</envar> you provide.</para>
- <para>Because the Docker image's <envar>GUACAMOLE_HOME</envar> environment variable must
- point to a directory <emphasis>within the container</emphasis>, you will need to
- expose your custom <envar>GUACAMOLE_HOME</envar> to the container using the
- <option>-v</option> option of <command>docker run</command>. The container
- directory chosen can then be referenced in the <envar>GUACAMOLE_HOME</envar>
- environment variable, and the image will handle the rest automatically:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> run --name <replaceable>some-guacamole</replaceable> \
- ...
- <emphasis>-v <replaceable>/local/path</replaceable>:<replaceable>/some-directory</replaceable> \
- -e GUACAMOLE_HOME=<replaceable>/some-directory</replaceable> \</emphasis>
- -d -p 8080:8080 guacamole/guacamole</screen>
- </informalexample>
- </section>
- <section xml:id="verifying-guacamole-docker">
- <title>Verifying the Guacamole install</title>
- <para>Once the Guacamole image is running, Guacamole should be accessible at
- <uri>http://<replaceable>HOSTNAME</replaceable>:8080/guacamole/</uri>, where
- <replaceable>HOSTNAME</replaceable> is the hostname or address of the machine
- hosting Docker, and you <emphasis>should</emphasis> a login screen. If using MySQL
- or PostgreSQL, the database initialization scripts will have created a default
- administrative user called "<systemitem>guacadmin</systemitem>" with the password
- "<systemitem>guacadmin</systemitem>". <emphasis>You should log in and change
- your password immediately.</emphasis> If using LDAP, you should be able to log
- in as any valid user within your LDAP directory.</para>
- <para>If you cannot access Guacamole, or you do not see a login screen, check Docker's
- logs using the <command>docker logs</command> command to determine if something is
- wrong. Configuration parameters may have been given incorrectly, or the database may
- be improperly initialized:</para>
- <informalexample>
- <screen><prompt>$</prompt> <command>docker</command> logs <replaceable>some-guacamole</replaceable></screen>
- </informalexample>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/duo-auth.xml b/src/chapters/duo-auth.xml
deleted file mode 100644
index c02f5ef..0000000
--- a/src/chapters/duo-auth.xml
+++ /dev/null
@@ -1,229 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="duo-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>Duo two-factor authentication</title>
- <indexterm>
- <primary>Duo</primary>
- </indexterm>
- <para>Guacamole supports Duo as a second authentication factor, layered on top of any other
- authentication extension, including those available from the main project website. The Duo
- authentication extension allows users to be additionally verified against the Duo service
- before the authentication process is allowed to succeed.</para>
- <important>
- <para>This chapter involves modifying the contents of <varname>GUACAMOLE_HOME</varname> -
- the Guacamole configuration directory. If you are unsure where
- <varname>GUACAMOLE_HOME</varname> is located on your system, please consult <xref
- linkend="configuring-guacamole"/> before proceeding.</para>
- </important>
- <section xml:id="duo-architecture">
- <title>How Duo works with Guacamole</title>
- <para>Guacamole provides support for Duo as a second authentication factor. To make use of
- the Duo authentication extension, some other authentication mechanism will need be
- configured, as well. When a user attempts to log into Guacamole, other installed
- authentication methods will be queried first:</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/duo-auth-factor-1.png" format="PNG"
- contentwidth="2in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- <para>Only after authentication has succeeded with one of those methods will Guacamole reach
- out to Duo to obtain additional verification of user identity:</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/duo-auth-factor-2.png" format="PNG"
- contentwidth="4in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- <para>If both the initial authentication attempt and verification through Duo succeed, the
- user will be allowed in. If either mechanism fails, access to Guacamole is
- denied.</para>
- </section>
- <section xml:id="duo-downloading">
- <title>Downloading the Duo extension</title>
- <para>The Duo authentication extension is available separately from the main
- <filename>guacamole.war</filename>. The link for this and all other
- officially-supported and compatible extensions for a particular version of Guacamole are
- provided on the release notes for that version. You can find the release notes for
- current versions of Guacamole here: <link
- xlink:href="http://guacamole.apache.org/releases/"
- >http://guacamole.apache.org/releases/</link>.</para>
- <para>The Duo authentication extension is packaged as a <filename>.tar.gz</filename> file
- containing only the extension itself,
- <filename>guacamole-auth-duo-1.3.0.jar</filename>, which must ultimately
- be placed in <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </section>
- <section xml:id="installing-duo-auth">
- <title>Installing Duo authentication</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- located within the <filename>GUACAMOLE_HOME/extensions</filename> directory. To install
- the Duo authentication extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Copy <filename>guacamole-auth-duo-1.3.0.jar</filename> within
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </step>
- <step>
- <para>Configure Guacamole to use Duo authentication, as described below.</para>
- </step>
- </procedure>
- <important>
- <para>You will need to restart Guacamole by restarting your servlet container in order
- to complete the installation. Doing this will disconnect all active users, so be
- sure that it is safe to do so prior to attempting installation. If you do not
- configure the Duo authentication properly, Guacamole will not start up again until
- the configuration is fixed.</para>
- </important>
- <section>
- <title xml:id="duo-guac-config">Adding Guacamole to Duo</title>
- <para>Duo does not provide a specific integration option for Guacamole, but Guacamole's
- Duo extension uses Duo's generic authentication API which they refer to as the "Web
- SDK". To use Guacamole with Duo, you will need to add it as a new "Web SDK"
- application from within the "Applications" tab of the admin panel of your Duo
- account:</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/duo-add-guacamole.png" format="PNG"
- contentwidth="6in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- <para>Within the settings of the newly-added application, rename the application to
- something more representative than "Web SDK". This application name is what will be
- presented to your users when they are prompted by Duo for additional
- authentication:</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/duo-rename-guacamole.png" format="PNG"
- contentwidth="6in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- <para>Once you've finished adding Guacamole as an "Web SDK" application, the
- configuration information required to configure Guacamole is listed within the
- application's "Details" section. You will need to copy the integration key, secret
- key, and API hostname - they will later be specified within
- <filename>guacamole.properties</filename>:</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/duo-copy-details.png" format="PNG"
- contentwidth="6in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
- <section xml:id="guac-duo-config">
- <title>Configuring Guacamole for Duo</title>
- <indexterm>
- <primary>configuring Duo</primary>
- </indexterm>
- <indexterm>
- <primary>Duo</primary>
- <secondary>configuration</secondary>
- </indexterm>
- <para>The application-specific configuration information retrieved from Duo must be
- added to <filename>guacamole.properties</filename> to describe how Guacamole should
- connect to the Duo service:</para>
- <variablelist>
- <varlistentry>
- <term><property>duo-api-hostname</property></term>
- <listitem>
- <para>The hostname of the Duo API endpoint to be used to verify user
- identities. This will usually be in the form
- "<uri>api-<replaceable>XXXXXXXX</replaceable>.duosecurity.com</uri>",
- where "<replaceable>XXXXXXXX</replaceable>" is some arbitrary
- alphanumeric value assigned by Duo. This value will have been generated
- by Duo when you added Guacamole as an "Web SDK" application, and can be
- found within the application details in the "API hostname" field.
- <emphasis>This value is required.</emphasis></para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>duo-integration-key</property></term>
- <listitem>
- <para>The integration key provided for Guacamole by Duo. This value will
- have been generated by Duo when you added Guacamole as an "Web SDK"
- application, and can be found within the application details in the
- "Integration key" field. <emphasis>This value is required and must be
- EXACTLY 20 characters.</emphasis></para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>duo-secret-key</property></term>
- <listitem>
- <para>The secret key provided for Guacamole by Duo. This value will have
- been generated by Duo when you added Guacamole as an "Web SDK"
- application, and can be found within the application details in the
- "Secret key" field. <emphasis>This value is required and must be EXACTLY
- 40 characters.</emphasis></para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>In addition to the above, <emphasis>you must also manually generate an
- "application key"</emphasis>. The application key is required by Duo's
- authentication API, but is not provided by Duo. It is an arbitrary value meant to be
- unique to each deployment of an application using their API.</para>
- <variablelist>
- <varlistentry>
- <term><property>duo-application-key</property></term>
- <listitem>
- <para>An arbitrary, random key which you manually generated for Guacamole.
- <emphasis>This value is required and must be AT LEAST 40
- characters.</emphasis></para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>The application key can be generated with any method as long as it is sufficiently
- random. There exist utilities which will do this for you, like
- <command>pwgen</command>:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>pwgen 40 1</userinput>
-<computeroutput>em1io4zievohneeseiwah0zie2raQuoo2ci5oBoo</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>Alternatively, one quick and fairly portable way to do this is to use the
- <command>dd</command> utility to copy random bytes from the secure random device
- <filename>/dev/random</filename>, sending the data through a cryptographic hash
- tool with a sufficiently-long result, like <command>sha256sum</command>:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>dd if=/dev/random count=1 | sha256sum</userinput>
-<computeroutput>5d16d6bb86da73e7d1abd3286b21dcf3b3e707532e64ceebc7a008350d0d485d -</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- </section>
- <section xml:id="completing-duo-install">
- <title>Completing the installation</title>
- <para>Guacamole will only reread <filename>guacamole.properties</filename> and load
- newly-installed extensions during startup, so your servlet container will need to be
- restarted before Duo authentication will take effect. Restart your servlet container
- and give the new authentication a try.</para>
- <para>
- <important>
- <para>You only need to restart your servlet container. <emphasis>You do not need
- to restart <package>guacd</package></emphasis>.</para>
- <para><package>guacd</package> is completely independent of the web application
- and does not deal with <filename>guacamole.properties</filename> or the
- authentication system in any way. Since you are already restarting the
- servlet container, restarting <package>guacd</package> as well technically
- won't hurt anything, but doing so is completely pointless.</para>
- </important>
- </para>
- <para>If Guacamole does not come back online after restarting your servlet container,
- check the logs. Problems in the configuration of the Duo extension may prevent
- Guacamole from starting up, and any such errors will be recorded in the logs of your
- servlet container.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/event-listeners.xml b/src/chapters/event-listeners.xml
deleted file mode 100644
index 5d5b50f..0000000
--- a/src/chapters/event-listeners.xml
+++ /dev/null
@@ -1,352 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="event-listeners" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Event listeners</title>
- <indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>events</primary>
- <secondary>listeners</secondary>
- </indexterm>
- <para>Guacamole supports the delivery of event notifications to custom extensions.
- Developers can use listener extensions to integrate custom handling of events such as
- successful and failed authentications, and requests to connect and disconnect tunnels to
- desktop environments.</para>
- <para>A listener extension could be used, for example, to record authentication attempts in
- an external database for security auditing or alerting. By listening to tunnel lifecycle
- events, a listener extension could be used to help coordinate startup and shutdown of
- machine resources; particularly useful in cloud environments where minimizing
- running-but-idle resources is an important cost savings measure.</para>
- <para>For certain <emphasis>vetoable</emphasis> events, an event listener can even influence
- Guacamole's behavior. For example, a listener can veto a successful authentication,
- effectively causing the authentication to be considered failed. Similarly, a listener
- can veto a tunnel connection, effectively preventing the tunnel from being connected to
- a virtual desktop resource.</para>
- <para>Custom event listeners are packaged using the same extension mechanism used for
- custom authentication providers. A single listener extension can include any number of
- classes that implement the listener interface. A single extension module can also include
- any combination of authentication providers and listeners, so developers can easily
- combine authentication providers with listeners designed to support them.</para>
- <para>To demonstrate the principles involved in receiving Guacamole event notifications, we
- will implement a simple listener extension that logs authentication events. While our
- approach simply writes event details to the same log used by the Guacamole web application,
- a listener could process these events in arbitrary ways, limited only by the imagination and
- ingenuity of the developer.</para>
- <section xml:id="custom-event-listener-skeleton">
- <title>A Guacamole listener extension skeleton</title>
- <para>For simplicity's sake, and because this is how things are done upstream in the
- Guacamole project, we will use Maven to build our extension.</para>
- <para>The bare minimum required for a Guacamole listener extension is a
- <filename>pom.xml</filename> file listing guacamole-ext as a dependency, a single
- <filename>.java</filename> file implementing our stub of a listener, and a
- <filename>guac-manifest.json</filename> file describing the extension and pointing
- to our listener class.</para>
- <example>
- <title>Barebones <filename>pom.xml</filename> required for a simple listener
- extension that writes log messages for received events.</title>
- <programlisting><project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
- http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-listener-tutorial</artifactId>
- <packaging>jar</packaging>
- <version>1.3.0</version>
- <name>guacamole-listener-tutorial</name>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
-
- <build>
- <plugins>
-
- <!-- Written for 1.6 -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.3</version>
- <configuration>
- <source>1.6</source>
- <target>1.6</target>
- </configuration>
- </plugin>
-
- </plugins>
- </build>
-
- <dependencies>
-
- <!-- Guacamole Extension API -->
- <dependency>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-ext</artifactId>
- <version>1.3.0</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Slf4j API -->
- <!-- This is needed only if your listener wants to
- write to the Guacamole web application log -->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.7.7</version>
- <scope>provided</scope>
- </dependency>
-
- </dependencies>
-
-</project></programlisting>
- </example>
- <para>Naturally, we need the actual listener extension skeleton code. While you can
- put this in whatever file and package you want, for the sake of this tutorial, we will
- assume you are using
- <classname>org.apache.guacamole.event.TutorialListener</classname>.</para>
- <para>For now, we won't actually do anything other than log the fact that an event
- notification was received. At this point, we're just creating the skeleton for our
- listener extension.</para>
- <example>
- <title>A skeleton <classname>TutorialListener</classname></title>
- <programlisting>package org.apache.guacamole.event;
-
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.net.event.listener.Listener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A Listener implementation intended to demonstrate basic use
- * of Guacamole's listener extension API.
- */
-public class TutorialListener implements Listener {
-
- private static final Logger logger =
- LoggerFactory.getLogger(TutorialListener.class);
-
- @Override
- public void handleEvent(Object event) throws GuacamoleException {
- logger.info("received Guacamole event notification");
- }
-
-}</programlisting>
- </example>
- <para>To conform with Maven, this skeleton file must be placed within
- <filename>src/main/java/org/apache/guacamole/event</filename> as
- <filename>TutorialListener.java</filename>.</para>
- <para>As you can see, implementing a listener is quite simple. There is a single
- <classname>Listener</classname> interface to implement. All Guacamole event
- notifications will be delivered to your code by invoking the
- <methodname>handleEvent</methodname> method. We will see shortly how to use
- the passed event object to get the details of the event itself.
- </para>
- <para>The only remaining piece for the overall skeleton to be complete is a
- <filename>guac-manifest.json</filename> file. <emphasis>This file is absolutely
- required for all Guacamole extensions.</emphasis> The
- <filename>guac-manifest.json</filename> format is described in more detail in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="guacamole-ext"/>. It provides
- for quite a few properties, but for our listener extension we are mainly
- interested in the Guacamole version sanity check (to make sure an extension built for
- the API of Guacamole version X is not accidentally used against version Y) and telling
- Guacamole where to find our listener class.</para>
- <para>The Guacamole extension format requires that <filename>guac-manifest.json</filename>
- be placed in the root directory of the extension <filename>.jar</filename> file. To
- accomplish this with Maven, we place it within the
- <filename>src/main/resources</filename> directory. Maven will automatically pick it
- up during the build and include it within the <filename>.jar</filename>.</para>
- <example>
- <title>The required <filename>guac-manifest.json</filename></title>
- <programlisting>{
-
- "guacamoleVersion" : "1.3.0",
-
- "name" : "Tutorial Listener Extension",
- "namespace" : "guac-listener-tutorial",
-
- "listeners" : [
- "org.apache.guacamole.event.TutorialListener"
- ]
-
-}</programlisting>
- </example>
- </section>
- <section xml:id="custom-listener-building">
- <title>Building the extension</title>
- <para>Once all three of the above files are in place, the extension should build successfully
- even though it is just a skeleton at this point.</para>
- <informalexample>
- <screen><prompt>$</prompt> mvn package
-<computeroutput>[INFO] Scanning for projects...
-[INFO] ---------------------------------------------------------------
-[INFO] Building guacamole-listener-tutorial 1.3.0
-[INFO] ---------------------------------------------------------------
-...
-[INFO] ---------------------------------------------------------------
-[INFO] BUILD SUCCESS
-[INFO] ---------------------------------------------------------------
-[INFO] Total time: 1.297 s
-[INFO] Finished at: 2017-10-08T13:12:39-04:00
-[INFO] Final Memory: 19M/306M
-[INFO] ---------------------------------------------------------------</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>Assuming you see the "<computeroutput>BUILD SUCCESS</computeroutput>" message when you
- build the extension, there will be a new file,
- <filename>target/guacamole-listener-tutorial-1.3.0.jar</filename>, which can be
- installed within Guacamole (see <xref xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="custom-listener-installing"/> at the end of this chapter). It should log
- event notifications that occur during, for example, authentication attempts.
- If you changed the name or version of the project
- in the <filename>pom.xml</filename> file, the name of this new <filename>.jar</filename>
- file will be different, but it can still be found within
- <filename>target/</filename>.</para>
- </section>
- <section xml:id="custom-listener-event-handling">
- <title>Handling events</title>
- <para>The Guacamole <classname>Listener</classname> interface represents a low-level event
- handling API. A listener is notified of every event generated by Guacamole. The listener
- must examine the event type to determine whether the event is of interest, and if so to
- dispatch the event to the appropriate entry point.</para>
- <para>The event types that can be produced by Guacamole are described in the
- <package>org.apache.guacamole.net.event</package> package of the <package>guacamole-ext</package>
- API. In this package you will find several concrete event types as well as interfaces that
- describe common characteristics of certain of event types. You can use any of these types
- to distinguish the events received by your listener, and to examine properties of an event
- of a given type.</para>
- <para>Suppose we wish to log authentication success and failure events, while ignoring all other
- event types. The <classname>AuthenticationSuccessEvent</classname> and
- <classname>AuthenticationFailureEvent</classname> types are used to notify a listener
- of authentication events. We can simply check whether a received event is of one of
- these types and, if so, log an appropriate message.</para>
- <example>
- <title>Using the event type to log an authentication success or failure</title>
- <programlisting>package org.apache.guacamole.event;
-
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.net.event.AuthenticationFailureEvent;
-import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
-import org.apache.guacamole.net.event.listener.Listener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A Listener that logs authentication success and failure events.
- */
-public class TutorialListener implements Listener {
-
- private static final Logger logger =
- LoggerFactory.getLogger(TutorialListener.class);
-
- @Override
- public void handleEvent(Object event) throws GuacamoleException {
-
- if (event instanceof AuthenticationSuccessEvent) {
- logger.info("successful authentication for user {}",
- ((AuthenticationSuccessEvent) event)
- .getCredentials().getUsername());
- }
- else if (event instanceof AuthenticationFailureEvent) {
- logger.info("failed authentication for user {}",
- ((AuthenticationFailureEvent) event)
- .getCredentials().getUsername());
- }
- }
-
-}</programlisting>
- </example>
- <para>In our example, we use <code>instanceof</code> to check for the two event types of
- interest to our listener. Once we have identified an event of interest, we can safely
- cast the event type to access properties of the event.</para>
- <para>The extension is now complete and can be built as described earlier in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="custom-listener-building"/>
- and installed as described below in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="custom-listener-installing"/>.</para>
- </section>
- <section xml:id="custom-listener-veto">
- <title>Influencing Guacamole by event veto</title>
- <para>An implementation of the <methodname>handleEvent</methodname> method is permitted to
- throw any <classname>GuacamoleException</classname>. For certain <emphasis>vetoable</emphasis>
- event types, throwing a <classname>GuacamoleException</classname> serves to effectively
- veto the action that resulted in the event notification. See the API documentation for
- <package>guacamole-ext</package> to learn more about vetoable event types.</para>
- <para>As an (admittedly contrived) example, suppose we want to prevent a user named
- "guacadmin" from accessing Guacamole. For whatever reason, we don't wish to remove or disable
- the auth database entry for this user. In this case we can use a listener to "blacklist" this
- user, preventing access to Guacamole. In the listener, when we get an
- <classname>AuthenticationSuccessEvent</classname> we can check to see if the user is
- "guacadmin" and, if so, throw an exception to prevent this user from logging in to
- Guacamole.</para>
- <example>
- <title>Vetoing an event by throwing a <classname>GuacamoleException</classname></title>
- <programlisting>package org.apache.guacamole.event;
-
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.GuacamoleSecurityException;
-import org.apache.guacamole.net.event.AuthenticationFailureEvent;
-import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
-import org.apache.guacamole.net.event.listener.Listener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A Listener that logs authentication success and failure events
- * and prevents the "guacadmin" user from logging in by throwing
- * a GuacamoleSecurityException.
- */
-public class TutorialListener implements Listener {
-
- private static final Logger logger =
- LoggerFactory.getLogger(TutorialListener.class);
-
- @Override
- public void handleEvent(Object event) throws GuacamoleException {
-
- if (event instanceof AuthenticationSuccessEvent) {
- final String username = ((AuthenticationSuccessEvent) event)
- .getCredentials().getUsername();
-
- if ("guacadmin".equals(username)) {
- logger.warn("user {} is blacklisted", username);
- throw new GuacamoleSecurityException(
- "User '" + username + "' is blacklisted");
- }
-
- logger.info("successful authentication for user {}", username);
- }
- else if (event instanceof AuthenticationFailureEvent) {
- logger.info("failed authentication for user {}",
- ((AuthenticationFailureEvent) event)
- .getCredentials().getUsername());
- }
- }
-
-}</programlisting>
- </example>
- <para>If our Guacamole user database contains a user named "guacadmin", and we build and
- install this listener extension, we will find that an attempt to log in as this user
- now results in a message in the UI indicating that the user is blacklisted. If we
- examine the Guacamole log, we will see the message indicating that the user is
- blacklisted. Because the successful authentication was vetoed, Guacamole sends a
- subsequent authentication failure notification, which we see logged as well.</para>
- </section>
- <section xml:id="custom-listener-installing">
- <title>Installing the extension</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- installed by being placed within <filename>GUACAMOLE_HOME/extensions</filename>, and
- this extension is no different. As described in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="configuring-guacamole"/>,
- <varname>GUACAMOLE_HOME</varname> is a placeholder used to refer to the directory
- that Guacamole uses to locate its configuration files and extensions. Typically, this
- will be the <filename>.guacamole</filename> directory within the home directory of the
- user running Tomcat.</para>
- <para>To install your extension, copy the
- <filename>target/guacamole-listener-tutorial-1.3.0.jar</filename> file into
- <filename>GUACAMOLE_HOME/extensions</filename> and restart Tomcat. Guacamole will
- automatically load your extension, logging an informative message that it has done
- so:</para>
- <informalexample>
- <screen>Extension "Tutorial Listener Extension" loaded.</screen>
- </informalexample>
- </section>
-</chapter>
diff --git a/src/chapters/guacamole-common-js.xml b/src/chapters/guacamole-common-js.xml
deleted file mode 100644
index 84d4d76..0000000
--- a/src/chapters/guacamole-common-js.xml
+++ /dev/null
@@ -1,429 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="guacamole-common-js" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>guacamole-common-js</title>
- <indexterm>
- <primary>API</primary>
- <secondary>JavaScript</secondary>
- </indexterm>
- <indexterm>
- <primary>guacamole-common-js</primary>
- </indexterm>
- <para>The Guacamole project provides a JavaScript API for interfacing with
- other components that conform to the design of Guacamole, such as
- projects using libguac or guacamole-common. This API is called
- guacamole-common-js.</para>
- <para>guacamole-common-js provides a JavaScript implementation of a
- Guacamole client, as well as tunneling mechanisms for getting protocol
- data out of JavaScript and into guacd or the server side of a web
- application.</para>
- <para>For convenience, it also provides mouse and keyboard abstraction objects that translate
- JavaScript mouse, touch, and keyboard events into consistent data that Guacamole can more
- easily digest. The extendable on-screen keyboard that was developed for the Guacamole web
- application is also included.</para>
- <section xml:id="guacamole-client">
- <title>Guacamole client</title>
- <para>The main benefit to using the JavaScript API is the full Guacamole
- client implementation, which implements all Guacamole instructions,
- and makes use of the tunnel implementations provided by both the
- JavaScript and Java APIs.</para>
- <para>Using the Guacamole client is straightforward. The client, like
- all other objects within the JavaScript API, is within the
- <code>Guacamole</code> namespace. It is instantiated given an
- existing, unconnected tunnel:</para>
- <informalexample>
- <programlisting>var client = new Guacamole.Client(tunnel);</programlisting>
- </informalexample>
- <para>Once you have the client, it won't immediately appear within the
- DOM. You need to add its display element manually:</para>
- <informalexample>
- <programlisting>document.body.appendChild(client.getDisplay().getElement());</programlisting>
- </informalexample>
- <para>At this point, the client will be visible, rendering all updates
- as soon as they are received through the tunnel.</para>
- <informalexample>
- <programlisting>client.connect();</programlisting>
- </informalexample>
- <para>It is possible to pass arbitrary data to the tunnel during
- connection which can be used for authentication or for choosing a
- particular connection. When the <methodname>connect()</methodname>
- function of the Guacamole client is called, it in turn calls the
- <methodname>connect()</methodname> function of the tunnel
- originally given to the client, establishing a connection.</para>
- <important>
- <para>When creating the <classname>Guacamole.Client</classname>, the
- tunnel used must not already be connected. The
- <classname>Guacamole.Client</classname> will call the
- <methodname>connect()</methodname> function for you when its
- own <methodname>connect()</methodname> function is invoked. If
- the tunnel is already connected when it is given to the
- <classname>Guacamole.Client</classname>, connection may not
- work at all.</para>
- </important>
- <para>In general, all instructions available within the Guacamole
- protocol are automatically handled by the Guacamole client,
- including instructions related to audio and video. The only
- instructions which you must handle yourself are "name" (used to name
- the connection), "clipboard" (used to update clipboard data on the
- client side), and "error" (used when something goes wrong
- server-side). Each of these instructions has a corresponding event
- handler; you need only supply functions to handle these events. If
- any of these event handlers are left unset, the corresponding
- instructions are simply ignored.</para>
- </section>
- <section xml:id="http-tunnel">
- <title>HTTP tunnel</title>
- <para>Both the Java and JavaScript API implement corresponding ends of
- an HTTP tunnel, based on
- <classname>XMLHttpRequest</classname>.</para>
- <para>The tunnel is a true stream - there is no polling. An initial
- request is made from the JavaScript side, and this request is
- handled on the Java side. While this request is open, data is
- streamed along the connection, and instructions within this stream
- are handled as soon as they are received by the client.</para>
- <para>While data is being streamed along this existing connection, a
- second connection attempt is made. Data continues to be streamed
- along the original connection until the server receives and handles
- the second request, at which point the original connection closes
- and the stream is transferred to the new connection.</para>
- <para>This process repeats, alternating between active streams, thus
- creating an unbroken sequence of instructions, while also allowing
- JavaScript to free any memory used by the previously active
- connection.</para>
- <para>The tunnel is created by supplying the relative URL to the
- server-side tunnel servlet:</para>
- <informalexample>
- <programlisting>var tunnel = new Guacamole.Tunnel("tunnel");</programlisting>
- </informalexample>
- <para>Once created, the tunnel can be passed to a
- <classname>Guacamole.Client</classname> for use in a Guacamole
- connection.</para>
- <para>The tunnel actually takes care of the Guacamole protocol parsing
- on behalf of the client, triggering "oninstruction" events for every
- instruction received, splitting each element into elements of an
- array so that the client doesn't have to.</para>
- </section>
- <section xml:id="input-abstraction">
- <title>Input abstraction</title>
- <para>Browsers can be rather finicky when it comes to keyboard and mouse
- input, not to mention touch events. There is little agreement on
- which keyboard events get fired when, and what detail about the
- event is made available to JavaScript. Touch and mouse events can
- also cause confusion, as most browsers will generate
- <emphasis>both</emphasis> events when the user touches the
- screen (for compatibility with JavaScript code that only handles
- mouse events), making it more difficult for applications to support
- both mouse and touch independently.</para>
- <para>The Guacamole JavaScript API abstracts mouse, keyboard, and touch
- interaction, providing several helper objects which act as an
- abstract interface between you and the browser events.</para>
- <section xml:id="guacamole-mouse">
- <title>Mouse</title>
- <para>Mouse event abstraction is provided by the
- <classname>Guacamole.Mouse</classname> object. Given an
- arbitrary DOM element, <classname>Guacamole.Mouse</classname>
- triggers <property>onmousedown</property>,
- <property>onmousemove</property>, and
- <property>onmouseup</property> events which are consistent
- across browsers. This object only response. to true mouse
- events. Mouse events which are actually the result of touch
- events are ignored.</para>
- <informalexample>
- <programlisting>var element = document.getElementById("some-arbitrary-id");
-var mouse = new Guacamole.Mouse(element);
-
-mouse.onmousedown =
-mouse.onmousemove =
-mouse.onmouseup = function(state) {
-
- // Do something with the mouse state received ...
-
-};</programlisting>
- </informalexample>
- <para>The handles of each event are given an instance of
- <classname>Guacamole.Mouse.State</classname> which
- represents the current state of the mouse, containing the state
- of each button (including the scroll wheel) as well as the X and
- Y coordinates of the pointer in pixels.</para>
- </section>
- <section xml:id="guacamole-touch">
- <title>Touch</title>
- <para>Touch event abstraction is provided by either
- <classname>Guacamole.Touchpad</classname> (emulates a
- touchpad to generate artificial mouse events) or
- <classname>Guacamole.Touchscreen</classname> (emulates a
- touchscreen, again generating artificial mouse events).
- Guacamole uses the touchpad emulation, as this provides the most
- flexibility and mouse-like features, including scrollwheel and
- clicking with different buttons, but your preferences may
- differ.</para>
- <informalexample>
- <programlisting>var element = document.getElementById("some-arbitrary-id");
-var touch = new Guacamole.Touchpad(element); // or Guacamole.Touchscreen
-
-touch.onmousedown =
-touch.onmousemove =
-touch.onmouseup = function(state) {
-
- // Do something with the mouse state received ...
-
-};</programlisting>
- </informalexample>
- <para>Note that even though these objects are touch-specific, they
- still provide mouse events. The state object given to the event
- handlers of each event is still an instance of
- <classname>Guacamole.Mouse.State</classname>.</para>
- <para>Ultimately, you could assign the same event handler to all the
- events of both an instance of
- <classname>Guacamole.Mouse</classname> as well as
- <classname>Guacamole.Touchscreen</classname> or
- <classname>Guacamole.Touchpad</classname>, and you would
- magically gain mouse and touch support. This support, being
- driven by the needs of remote desktop, is naturally geared
- around the mouse and providing a reasonable means of interacting
- with it. For an actual mouse, events are translated simply and
- literally, while touch events go through additional emulation
- and heuristics. From the perspective of the user and the code,
- this is all transparent.</para>
- </section>
- <section xml:id="guacamole-keyboard">
- <title>Keyboard</title>
- <para>Keyboard events in Guacamole are abstracted with the
- <classname>Guacamole.Keyboard</classname> object as only
- keyup and keydown events; there is no keypress like there is in
- JavaScript. Further, all the craziness of keycodes vs. scancodes
- vs. key identifiers normally present across browsers is
- abstracted away. All your event handlers will see is an X11
- keysym, which represent every key unambiguously. Conveniently,
- X11 keysyms are also what the Guacamole protocol requires, so if
- you want to use <classname>Guacamole.Keyboard</classname> to
- drive key events sent over the Guacamole protocol, everything
- can be connected directly.</para>
- <para>Just like the other input abstraction objects,
- <classname>Guacamole.Keyboard</classname> requires a DOM
- element as an event target. Only key events directed at this
- element will be handled.</para>
- <informalexample>
- <programlisting>var keyboard = new Guacamole.Keyboard(document);
-
-keyboard.onkeydown = function(keysym) {
- // Do something ...
-};
-
-keyboard.onkeyup = function(keysym) {
- // Do something ...
-};</programlisting>
- </informalexample>
- <para>In this case, we are using <classname>document</classname> as
- the event target, thus receiving all key events while the
- browser window (or tab) has focus.</para>
- </section>
- </section>
- <section xml:id="on-screen-keyboard">
- <title>On-screen keyboard</title>
- <para>The Guacamole JavaScript API also provides an extendable on-screen
- keyboard, <classname>Guacamole.OnScreenKeyboard</classname>, which
- requires the URL of an XML file describing the keyboard layout. The
- on-screen keyboard object provides no hard-coded layout information;
- the keyboard layout is described entirely within the XML layout
- file.</para>
- <section xml:id="keyboard-layouts">
- <title>Keyboard layouts</title>
- <para>The keyboard layout XML included in the Guacamole web
- application would be a good place to start regarding how these
- layout files are written, but in general, the keyboard is simply
- a set of rows or columns, denoted with <code><row></code> and
- <code><column></code> tags respectively, where each can
- be nested within the other as desired.</para>
- <para>Each key is represented with a <code><key></code> tag, but
- this is not what the user sees, nor what generates the key
- event. Each key contains any number of <code><cap></code>
- tags, which represent the visible part of the key. The cap
- describes which X11 keysym will be sent when the key is pressed.
- Each cap can be associated with any combination of arbitrary
- modifier flags which dictate when that cap is active.</para>
- <para>For example:</para>
- <informalexample>
- <programlisting><keyboard lang="en_US" layout="example" size="5">
- <row>
- <key size="4">
- <cap modifier="shift" keysym="0xFFE1">Shift</cap>
- </key>
- <key>
- <cap>a</cap>
- <cap if="shift">A</cap>
- </key>
- </row>
-</keyboard></programlisting>
- </informalexample>
- <para>Here we have a very simple keyboard which defines only two
- keys: "shift" (a modifier) and the letter "a". When "shift" is
- pressed, it sets the "shift" modifier, affecting other keys in
- the keyboard. The "a" key has two caps: one lowercase (the
- default) and one uppercase (which requires the shift modifier to
- be active).</para>
- <para>Notice that the shift key needed the keysym explicitly
- specified, while the "a" key did not. This is because the
- on-screen keyboard will automatically derive the correct keysym
- from the text of the key cap if the text contains only a single
- character.</para>
- </section>
- <section xml:id="displaying-osk">
- <title>Displaying the keyboard</title>
- <para>Once you have a keyboard layout available, adding an on-screen
- keyboard to your application is simple:</para>
- <informalexample>
- <programlisting>// Add keyboard to body
-var keyboard = new Guacamole.OnScreenKeyboard("path/to/layout.xml");
-document.body.appendChild(keyboard.getElement());
-
-// Set size of keyboard to 100 pixels
-keyboard.resize(100);</programlisting>
- </informalexample>
- <para>Here, we have explicitly specified the width of the keyboard
- as 100 pixels. Normally, you would determine this by inspecting
- the width of the containing component, or by deciding on a
- reasonable width beforehand. Once the width is given, the height
- of the keyboard is determined based on the arrangement of each
- row.</para>
- </section>
- <section xml:id="styling-the-keyboard">
- <title>Styling the keyboard</title>
- <para>While the <classname>Guacamole.OnScreenKeyboard</classname>
- object will handle most of the layout, you will still need to
- style everything yourself with CSS to get the elements to render
- properly and the keys to change state when clicked or activated.
- It defines several CSS classes, which you will need to manually
- style to get things looking as desired:</para>
- <variablelist>
- <varlistentry>
- <term><classname>guac-keyboard</classname></term>
- <listitem>
- <para>This class is assigned to the root element
- containing the entire keyboard, returned by
- <methodname>getElement()</methodname>,</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-row</classname></term>
- <listitem>
- <para>Assigned to the <code>div</code> elements which
- contain each row.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-column</classname></term>
- <listitem>
- <para>Assigned to the <code>div</code> elements which
- contain each column.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-gap</classname></term>
- <listitem>
- <para>Assigned to any <code>div</code> elements created
- as a result of <code><gap></code> tags in the
- keyboard layout. <code><gap></code> tags are
- intended to behave as keys with no visible styling
- or caps.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-key-container</classname></term>
- <listitem>
- <para>Assigned to the <code>div</code> element which
- contains a key, and provides that key with its
- required dimensions. It is this element that will be
- scaled relative to the size specified in the layout
- XML and the size given to the <code>resize()</code>
- function.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-key</classname></term>
- <listitem>
- <para>Assigned to the <code>div</code> element which
- represents the actual key, not the cap. This element
- will not directly contain text, but it will contain
- all caps that this key can have. With clever CSS
- rules, you can take advantage of this and cause
- inactive caps to appear on the key in a corner (for
- example), or hide them entirely.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-cap</classname></term>
- <listitem>
- <para>Assigned to the <code>div</code> element
- representing a key cap. Each cap is a child of its
- corresponding key, and it is up to the author of the
- CSS rules to hide or show or reposition each cap
- appropriately. Each cap will contain the display
- text defined within the <code><cap></code>
- element in the layout XML.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-requires-<replaceable>MODIFIER</replaceable></classname></term>
- <listitem>
- <para>Added to the cap element when that cap requires a
- specific modifier.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-uses-<replaceable>MODIFIER</replaceable></classname></term>
- <listitem>
- <para>Added to the key element when any cap contained
- within it requires a specific modifier.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-modifier-<replaceable>MODIFIER</replaceable></classname></term>
- <listitem>
- <para>Added to and removed from the root keyboard
- element when a modifier key is activated or
- deactivated respectively.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><classname>guac-keyboard-pressed</classname></term>
- <listitem>
- <para>Added to and removed from any key element as it is
- pressed and released respectively.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <important>
- <para>The CSS rules required for the on-screen keyboard to work
- as expected can be quite complex. Looking over the CSS rules
- used by the on-screen keyboard in the Guacamole web
- application would be a good place to start to see how the
- appearance of each key can be driven through the simple
- class changes described above.</para>
- <para>Inspecting the elements of an active on-screen keyboard
- within the Guacamole web application with the developer
- tools of your favorite browser is also a good idea.</para>
- </important>
- </section>
- <section xml:id="osk-event-handling">
- <title>Handling key events</title>
- <para>Key events generated by the on-screen keyboard are identical
- to those of <classname>Guacamole.Keyboard</classname> in that
- they consist only of a single X11 keysym. Only keyup and keydown
- events exist, as before; there is no keypress event.</para>
- <informalexample>
- <programlisting>// Assuming we have an instance of Guacamole.OnScreenKeyboard already
-// called "keyboard"
-
-keyboard.onkeydown = function(keysym) {
- // Do something ...
-};
-
-keyboard.onkeyup = function(keysym) {
- // Do something ...
-};</programlisting>
- </informalexample>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/guacamole-common.xml b/src/chapters/guacamole-common.xml
deleted file mode 100644
index ee362d6..0000000
--- a/src/chapters/guacamole-common.xml
+++ /dev/null
@@ -1,162 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="guacamole-common" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title><package>guacamole-common</package></title>
- <indexterm>
- <primary>API</primary>
- <secondary>Java</secondary>
- </indexterm>
- <indexterm>
- <primary><package>guacamole-common</package></primary>
- </indexterm>
- <para>The Java API provided by the Guacamole project is called guacamole-common. It provides a
- basic means of tunneling data between the JavaScript client provided by guacamole-common-js
- and the native proxy daemon, guacd, and for dealing with the Guacamole protocol. The purpose
- of this library is to facilitate the creation of custom tunnels between the JavaScript
- client and guacd, allowing your Guacamole-driven web application to enforce its own security
- model, if any, and dictate exactly what connections are established.</para>
- <section xml:id="java-http-tunnel">
- <title>HTTP tunnel</title>
- <para>The Guacamole Java API implements the HTTP tunnel using a servlet
- called <classname>GuacamoleHTTPTunnelServlet</classname>. This
- servlet handles all requests coming to it over HTTP from the
- JavaScript client, and translated them into connect, read, or write
- requests, which each get dispatched to the
- <methodname>doConnect()</methodname>,
- <methodname>doRead()</methodname>, and
- <methodname>doWrite()</methodname> functions accordingly.</para>
- <para>Normally, you wouldn't touch the <methodname>doRead()</methodname>
- and <methodname>doWrite()</methodname> functions, as these have
- already been written to properly handle the requests of the
- JavaScript tunnel, and if you feel the need to touch these
- functions, you are probably better off writing your own tunnel
- implementation, although such a thing is difficult to do in a
- performant way.</para>
- <para>When developing an application based on the Guacamole API, you
- should use <classname>GuacamoleHTTPTunnelServlet</classname> by
- extending it, implementing your own version of
- <methodname>doConnect()</methodname>, which is the only abstract
- function it defines. The tutorial later in this book demonstrating
- how to write a Guacamole-based web application shows the basics of
- doing this, but generally, <methodname>doConnect()</methodname> is
- an excellent place for authentication or other validation, as it is
- the responsibility of <methodname>doConnect()</methodname> to create
- (or not create) the actual tunnel. If
- <methodname>doConnect()</methodname> does not create the tunnel,
- communication between the JavaScript client and guacd cannot take
- place, which is an ideal power to have as an authenticator.</para>
- <para>The <methodname>doConnect()</methodname> function is expected to return a new
- <classname>GuacamoleTunnel</classname>, but it is completely up to the
- implementation to decide how that tunnel is to be created. The already-implemented parts
- of <classname>GuacamoleHTTPTunnelServlet</classname> then return the unique identifier
- of this tunnel to the JavaScript client, allowing its own tunnel implementation to
- continue to communicate with the tunnel existing on the Java side.</para>
- <para>Instances of <classname>GuacamoleTunnel</classname> are created associated with a
- <classname>GuacamoleSocket</classname>, which is the abstract interface surrounding
- the low-level connection to guacd. Overall, there is a socket
- (<classname>GuacamoleSocket</classname>) which provides a TCP connection to guacd.
- This socket is exposed to <classname>GuacamoleTunnel</classname>, which provides
- abstract protocol access around what is actually (but secretly, through the abstraction
- of the API) a TCP socket.</para>
- <para>The Guacamole web application extends this tunnel servlet in order
- to implement authentication at the lowest possible level,
- effectively prohibiting communication between the client and any
- remote desktops unless they have properly authenticated. Your own
- implementation can be considerably simpler, especially if you don't
- need authentication:</para>
- <informalexample>
- <programlisting>public class MyGuacamoleTunnelServlet
- extends GuacamoleHTTPTunnelServlet {
-
- @Override
- protected GuacamoleTunnel doConnect(HttpServletRequest request)
- throws GuacamoleException {
-
- // Connect to guacd here (this is a STUB)
- GuacamoleSocket socket;
-
- // Return a new tunnel which uses the connected socket
- return new SimpleGuacamoleTunnel(socket);
-
- }
-
-}</programlisting>
- </informalexample>
- </section>
- <section xml:id="java-protocol-usage">
- <title>Using the Guacamole protocol</title>
- <para>guacamole-common provides basic low-level support for the
- Guacamole protocol. This low-level support is leveraged by the HTTP
- tunnel implementation to satisfy the requirements of the JavaScript
- client implementation, as the JavaScript client expects the
- handshake procedure to have already taken place. This support exists
- through the <classname>GuacamoleReader</classname> and
- <classname>GuacamoleWriter</classname> classes, which are
- similar to Java's <classname>Reader</classname> and
- <classname>Writer</classname> classes, except that they deal
- with the Guacamole protocol specifically, and thus have slightly
- different contracts.</para>
- <section xml:id="java-reading-protocol">
- <title><classname>GuacamoleReader</classname></title>
- <para><classname>GuacamoleReader</classname> provides a very basic
- <methodname>read()</methodname> function which is required
- to return one or more complete instructions in a
- <type>char</type> array. It also provides the typical
- <methodname>available()</methodname> function, which informs
- you whether <methodname>read()</methodname> is likely to block
- the next time it is called, and an even more abstract version of
- <methodname>read()</methodname> called
- <methodname>readInstruction()</methodname> which returns one
- instruction at a time, wrapped within a
- <classname>GuacamoleInstruction</classname> instance.</para>
- <para>Normally, you would not need to use this class yourself. It is
- used by <classname>ConfiguredGuacamoleSocket</classname> to
- complete the Guacamole protocol handshake procedure, and it is
- used by <classname>GuacamoleHTTPTunnelServlet</classname> within
- <methodname>doRead()</methodname> to implement the reading
- half of the tunnel.</para>
- <para>The only concrete implementation of
- <classname>GuacamoleReader</classname> is
- <classname>ReaderGuacamoleReader</classname>, which wraps a
- Java <classname>Reader</classname>, using that as the source for
- data to parse into Guacamole instructions. Again, you would not
- normally directly use this class, nor instantiate it yourself. A
- working, concrete instance of
- <classname>GuacamoleReader</classname> can be retrieved from
- any <classname>GuacamoleSocket</classname> or
- <classname>GuacamoleTunnel</classname>.</para>
- </section>
- <section xml:id="java-writing-protocol">
- <title><classname>GuacamoleWriter</classname></title>
- <para><classname>GuacamoleWriter</classname> provides a very basic
- <methodname>write()</methodname> function and a more
- abstract version called
- <methodname>writeInstruction()</methodname> which writes
- instances of <classname>GuacamoleInstruction</classname>. These
- functions are analogous to the <methodname>read()</methodname>
- and <methodname>readInstruction()</methodname> functions
- provided by <classname>GuacamoleReader</classname>, and have
- similar restrictions: the contract imposed by
- <methodname>write()</methodname> requires that written
- instructions be complete</para>
- <para>The only concrete implementation of
- <classname>GuacamoleWriter</classname> is
- <classname>WriterGuacamoleWriter</classname>, which wraps a
- Java <classname>Writer</classname>, using that as the
- destination for Guacamole instruction data, but you would not
- normally directly use this class, nor instantiate it yourself.
- It is used by <classname>ConfiguredGuacamoleSocket</classname>
- to complete the Guacamole protocol handshake procedure, and it
- is used by <classname>GuacamoleHTTPTunnelServlet</classname>
- within <methodname>doWrite()</methodname> to implement the
- writing half of the tunnel.</para>
- <para>If necessary, a <classname>GuacamoleWriter</classname> can be
- retrieved from any <classname>GuacamoleSocket</classname> or
- <classname>GuacamoleTunnel</classname>, but in most cases,
- the classes provided by the Guacamole Java API which already use
- <classname>GuacamoleWriter</classname> will be
- sufficient.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/guacamole-ext.xml b/src/chapters/guacamole-ext.xml
deleted file mode 100644
index f7a1bba..0000000
--- a/src/chapters/guacamole-ext.xml
+++ /dev/null
@@ -1,822 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="guacamole-ext" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>guacamole-ext</title>
- <indexterm>
- <primary>API</primary>
- <secondary>Java</secondary>
- </indexterm>
- <indexterm>
- <primary>guacamole-ext</primary>
- </indexterm>
- <para>While not strictly part of the Java API provided by the Guacamole project, guacamole-ext
- is an API exposed by the Guacamole web application within a separate project such that
- extensions, specifically authentication providers, can be written to tweak Guacamole to fit
- well in existing deployments.</para>
- <para>Extensions to Guacamole can:</para>
- <orderedlist>
- <listitem>
- <para>Provide alternative authentication methods and sources of connection/user
- data.</para>
- </listitem>
- <listitem>
- <para>Provide event listeners that will be notified as Guacamole performs tasks such
- as authentication and tunnel connection.</para>
- </listitem>
- <listitem>
- <para>Theme or brand Guacamole through additional CSS files and static resources.</para>
- </listitem>
- <listitem>
- <para>Extend Guacamole's JavaScript code by providing JavaScript that will be loaded
- automatically.</para>
- </listitem>
- <listitem>
- <para>Add additional display languages, or alter the translation strings of existing
- languages.</para>
- </listitem>
- </orderedlist>
- <section xml:id="ext-file-format">
- <title>Guacamole extension format</title>
- <para>Guacamole extensions are standard Java <filename>.jar</filename> files which contain
- all classes and resources required by the extension, as well as the Guacamole extension
- manifest. There is no set structure to an extension except that the manifest must be in
- the root of the archive. Java classes and packages, if any, will be read from the
- <filename>.jar</filename> relative to the root, as well.</para>
- <para>Beyond this, the semantics and locations associated with all other resources within
- the extension are determined by the extension manifest alone.</para>
- <section xml:id="ext-manifest">
- <title>Extension manifest</title>
- <para>The Guacamole extension manifest is a single JSON file,
- <filename>guac-manifest.json</filename>, which describes the location of each
- resource, the type of each resource, and the version of Guacamole that the extension
- was built for. The manifest can contain the following properties:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3*"/>
- <thead>
- <row>
- <entry>Property</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><property>guacamoleVersion</property></entry>
- <entry>
- <para>The version string of the Guacamole release that this
- extension is written for. <emphasis>This property is required
- for all extensions.</emphasis> The special version string
- <code>"*"</code> can be used if the extension does not
- depend on a particular version of Guacamole, but be careful -
- this will bypass version compatibility checks, and should never
- be used if the extension does more than basic theming or
- branding.</para>
- </entry>
- </row>
- <row>
- <entry><property>name</property></entry>
- <entry>
- <para>A human-readable name for the extension. <emphasis>This
- property is required for all extensions.</emphasis> When
- your extension is successfully loaded, a message acknowledging
- the successful loading of your extension by name will be
- logged.</para>
- </entry>
- </row>
- <row>
- <entry><property>namespace</property></entry>
- <entry>
- <para>A unique string which identifies your extension.
- <emphasis>This property is required for all
- extensions.</emphasis> This string should be unique enough
- that it is unlikely to collide with the namespace of any other
- extension.</para>
- <para>If your extension contains static resources, those resources
- will be served at a path derived from the namespace provided
- here.</para>
- </entry>
- </row>
- <row>
- <entry><property>authProviders</property></entry>
- <entry>
- <para>An array of the classnames of all
- <classname>AuthenticationProvider</classname> subclasses
- provided by this extension.</para>
- </entry>
- </row>
- <row>
- <entry><property>listeners</property></entry>
- <entry>
- <para>An array of the classnames of all
- <classname>Listener</classname> subclasses
- provided by this extension.</para>
- </entry>
- </row>
- <row>
- <entry><property>js</property></entry>
- <entry>
- <para>An array of all JavaScript files within the extension. All
- paths within this array must be relative paths, and will be
- interpreted relative to the root of the archive.</para>
- <para>JavaScript files declared here will be automatically loaded
- when the web application loads within the user's browser.</para>
- </entry>
- </row>
- <row>
- <entry><property>css</property></entry>
- <entry>
- <para>An array of all CSS files within the extension. All paths
- within this array must be relative paths, and will be
- interpreted relative to the root of the archive.</para>
- <para>CSS files declared here will be automatically applied when the
- web application loads within the user's browser.</para>
- </entry>
- </row>
- <row>
- <entry><property>html</property></entry>
- <entry>
- <para>An array of all HTML files within the extension that should be
- used to update or replace existing HTML within the Guacamole
- interface. All paths within this array must be relative paths,
- and will be interpreted relative to the root of the
- archive.</para>
- <para>HTML files declared here will be automatically applied to
- other HTML within the Guacamole interface when the web
- application loads within the user's browser. The manner in which
- the files are applied is dictated by <tag><meta ...></tag>
- within those same files.</para>
- </entry>
- </row>
- <row>
- <entry><property>translations</property></entry>
- <entry>
- <para>An array of all translation files within the extension. All
- paths within this array must be relative paths, and will be
- interpreted relative to the root of the archive.</para>
- <para>Translation files declared here will be automatically added to
- the available languages. If a translation file provides a
- language that already exists within Guacamole, its strings will
- override the strings of the existing translation.</para>
- </entry>
- </row>
- <row>
- <entry><property>resources</property></entry>
- <entry>
- <para>An object where each property name is the name of a web
- resource file, and each value is the mimetype for that resource.
- All paths within this object must be relative paths, and will be
- interpreted relative to the root of the archive.</para>
- <para>Web resources declared here will be made available to the
- application at
- <filename>app/ext/<replaceable>NAMESPACE</replaceable>/<replaceable>PATH</replaceable></filename>,
- where <replaceable>NAMESPACE</replaceable> is the value of the
- <property>namespace</property> property, and
- <replaceable>PATH</replaceable> is the declared web resource
- filename.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>The only absolutely required properties are <property>guacamoleVersion</property>,
- <property>name</property>, and <property>namespace</property>, as they are used
- to identify the extension and for compatibility checks. The most minimal
- <filename>guac-manifest.json</filename> will look something like this:</para>
- <informalexample>
- <programlisting>{
- "guacamoleVersion" : "1.3.0",
- "name" : "My Extension",
- "namespace" : "my-extension"
-}</programlisting>
- </informalexample>
- <para>This will allow the extension to load, but does absolutely nothing otherwise.
- Lacking the semantic information provided by the other properties, no other files
- within the extension will be used. A typical <filename>guac-manifest.json</filename>
- for an extension providing theming or branding would be more involved:</para>
- <informalexample>
- <programlisting>{
-
- "guacamoleVersion" : "1.3.0",
-
- "name" : "My Extension",
- "namespace" : "my-extension",
-
- "css" : [ "theme.css" ],
-
- "html" : [ "loginDisclaimer.html" ],
-
- "resources" : {
- "images/logo.png" : "image/png",
- "images/cancel.png" : "image/png",
- "images/delete.png" : "image/png"
- }
-
-}</programlisting>
- </informalexample>
- </section>
- <section xml:id="ext-patch-html">
- <title>Updating existing HTML</title>
- <para>The existing HTML structure of Guacamole's interface can be modified by extensions
- through special "patch" HTML files declared by the <property>html</property>
- property in <filename>guac-manifest.json</filename>. These files are HTML fragments
- and are identical to any other HTML file except that they contain Guacamole-specific
- <tag>meta</tag> tags that instruct Guacamole to modify its own HTML in a
- particular way. Each <tag>meta</tag> tag takes the following form:</para>
- <informalexample>
- <programlisting><meta name="<replaceable>NAME</replaceable>" content="<replaceable>SELECTOR</replaceable>"></programlisting>
- </informalexample>
- <para>where <replaceable>SELECTOR</replaceable> is a CSS selector that matches the
- elements within the Guacamole interface that serve as a basis for the modification,
- and <replaceable>NAME</replaceable> is any one of the following defined
- modifications:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="4*"/>
- <thead>
- <row>
- <entry>Name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><property>before</property></entry>
- <entry>
- <para>Inserts the specified HTML immediately before any element
- matching the CSS selector.</para>
- </entry>
- </row>
- <row>
- <entry><property>after</property></entry>
- <entry>
- <para>Inserts the specified HTML immediately after any element
- matching the CSS selector.</para>
- </entry>
- </row>
- <row>
- <entry><property>replace</property></entry>
- <entry>
- <para>Replaces any element matching the CSS selector with the
- specified HTML.</para>
- </entry>
- </row>
- <row>
- <entry><property>before-children</property></entry>
- <entry>
- <para>Inserts the specified HTML immediately before the first child
- (if any) of any element matching the CSS selector. If a matching
- element has no children, the HTML simply becomes the entire
- contents of the matching element.</para>
- </entry>
- </row>
- <row>
- <entry><property>after-children</property></entry>
- <entry>
- <para>Inserts the specified HTML immediately after the last child
- (if any) of any element matching the CSS selector. If a matching
- element has no children, the HTML simply becomes the entire
- contents of the matching element.</para>
- </entry>
- </row>
- <row>
- <entry><property>replace-children</property></entry>
- <entry>
- <para>Replaces the entire contents of any element matching the CSS
- selector with the specified HTML.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>For example, to add a welcome message and link to some corporate privacy policy (a
- fairly common need), you would add an HTML file like the following:</para>
- <informalexample>
- <programlisting><meta name="after" content=".login-ui .login-dialog">
-
-<div class="welcome">
- <h2>Welcome to our Guacamole server!</h2>
- <p>
- Please be sure to read our <a href="/path/to/some/privacy.html">privacy
- policy</a> before continuing.
- </p>
-</div></programlisting>
- </informalexample>
- <para>After the extension is installed and Guacamole is restarted, the "welcome" div and
- its contents will automatically be inserted directly below the login dialog (the
- only element that would match <code>.login-ui .login-dialog</code>) as if they were
- part of Guacamole's HTML in the first place.</para>
- <para>An example of an extension that modifies style and HTML components for the purpose
- of providing custom "branding" of the Guacamole interface can be found in the
- <filename>doc/guacamole-branding-example</filename> directory of the guacamole-client
- source code, which can be found here: <link
- xlink:href="https://github.com/apache/guacamole-client/tree/master/doc/guacamole-branding-example" >https://github.com/apache/guacamole-client/tree/master/doc/guacamole-branding-example</link>.</para>
- </section>
- </section>
- <section xml:id="ext-environment">
- <title>Accessing the server configuration</title>
- <para>The configuration of the Guacamole server is exposed through the
- <classname>Environment</classname> interface, specifically the
- <classname>LocalEnvironment</classname> implementation of this interface. Through
- <classname>Environment</classname>, you can access all properties declared within
- <filename>guacamole.properties</filename>, determine the proper hostname/port of
- <package>guacd</package>, and access the contents of
- <varname>GUACAMOLE_HOME</varname>.</para>
- <section xml:id="ext-simple-config">
- <title>Custom properties</title>
- <para>If your extension requires generic, unstructured configuration parameters,
- <filename>guacamole.properties</filename> is a reasonable and simple location
- for them. The <classname>Environment</classname> interface provides direct access to
- <filename>guacamole.properties</filename> and simple mechanisms for reading and
- parsing the properties therein. The value of a property can be retrieved calling
- <methodname>getProperty()</methodname>, which will return
- <constant>null</constant> or a default value for undefined properties, or
- <methodname>getRequiredProperty()</methodname>, which will throw an exception
- for undefined properties.</para>
- <para>For convenience, guacamole-ext contains several pre-defined property base classes
- for common types:</para>
- <informaltable frame="all">
- <tgroup cols="3">
- <colspec colname="c1" colnum="1" colwidth="2*"/>
- <colspec colname="c2" colnum="2" colwidth="1*"/>
- <colspec colname="c3" colnum="3" colwidth="4*"/>
- <thead>
- <row>
- <entry>Class Name</entry>
- <entry>Value Type</entry>
- <entry>Interpretation</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><classname>BooleanGuacamoleProperty</classname></entry>
- <entry><classname>Boolean</classname></entry>
- <entry>The values "true" and "false" are parsed as their corresponding
- <classname>Boolean</classname> values. Any other value results
- in a parse error.</entry>
- </row>
- <row>
- <entry><classname>IntegerGuacamoleProperty</classname></entry>
- <entry><classname>Integer</classname></entry>
- <entry>Numeric strings are parsed as <classname>Integer</classname>
- values. Non-numeric strings will result in a parse error.</entry>
- </row>
- <row>
- <entry><classname>LongGuacamoleProperty</classname></entry>
- <entry><classname>Long</classname></entry>
- <entry>Numeric strings are parsed as <classname>Long</classname> values.
- Non-numeric strings will result in a parse error.</entry>
- </row>
- <row>
- <entry><classname>StringGuacamoleProperty</classname></entry>
- <entry><classname>String</classname></entry>
- <entry>The property value is returned as an untouched
- <classname>String</classname>. No parsing is performed, and
- parse errors cannot occur.</entry>
- </row>
- <row>
- <entry><classname>FileGuacamoleProperty</classname></entry>
- <entry><classname>File</classname></entry>
- <entry>The property is interpreted as a filename, and a new
- <classname>File</classname> pointing to that filename is
- returned. If the filename is invalid, a parse error will be thrown.
- Note that the file need not exist or be accessible for the filename
- to be valid.</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>To use these types, you must extend the base class, implementing the
- <methodname>getName()</methodname> function to identify your property.
- Typically, you would declare these properties as static members of some class
- containing all properties relevant to your extension:</para>
- <informalexample>
- <programlisting>public class MyProperties {
-
- public static <replaceable>MY_PROPERTY</replaceable> = new IntegerGuacamoleProperty() {
-
- @Override
- public String getName() { return "<replaceable>my-property</replaceable>"; }
-
- };
-
-}</programlisting>
- </informalexample>
- <para>Your property can then be retrieved with <methodname>getProperty()</methodname> or
- <methodname>getRequiredProperty()</methodname>:</para>
- <informalexample>
- <programlisting>Integer value = environment.getProperty(<replaceable>MyProperties.MY_PROPERTY</replaceable>);</programlisting>
- </informalexample>
- <para>If you need more sophisticated parsing, you can also implement your own property
- types by implementing the <classname>GuacamoleProperty</classname> interface. The
- only functions to implement are <methodname>getName()</methodname>, which returns
- the name of the property, and <methodname>parseValue()</methodname>, which parses a
- given string and returns its value.</para>
- </section>
- <section xml:id="ext-advanced-config">
- <title>Advanced configuration</title>
- <para>If you need more structured data than provided by simple properties, you can place
- completely arbitrary files in a hierarchy of your choosing anywhere within
- <varname>GUACAMOLE_HOME</varname> as long as you avoid placing your files in
- directories reserved for other purposes as described above.</para>
- <para>The Environment interface exposes the location of
- <varname>GUACAMOLE_HOME</varname> through the
- <methodname>getGuacamoleHome()</methodname> function. This function returns a
- standard Java <classname>File</classname> which can then be used to locate other
- files or directories within <varname>GUACAMOLE_HOME</varname>:</para>
- <informalexample>
- <programlisting>File myConfigFile = new File(environment.getGuacamoleHome(), "my-config.xml");</programlisting>
- <para>There is no guarantee that <varname>GUACAMOLE_HOME</varname> or your file will
- exist, and you should verify this before proceeding further in your extension's
- configuration process, but once this is done you can simply parse your file as
- you see fit.</para>
- </informalexample>
- </section>
- </section>
- <section xml:id="ext-auth-providers">
- <title>Authentication providers</title>
- <para>Guacamole's authentication system is driven by authentication providers, which are
- classes which implement the <classname>AuthenticationProvider</classname> interface
- defined by guacamole-ext. When any page within Guacamole is visited, the following
- process occurs:</para>
- <orderedlist>
- <listitem>
- <para>All currently installed extensions are polled, in lexicographic order of their
- filenames, by invoking the <methodname>getAuthenticatedUser()</methodname>
- function with a <classname>Credentials</classname> object constructed with the
- contents of the HTTP request.</para>
- <para>The credentials given are abstract. While the Credentials object provides
- convenience access to a traditional username and password,
- <emphasis>implementations are not required to use usernames and
- passwords</emphasis>. The entire contents of the HTTP request is at your
- disposal, including parameters, cookies, and SSL information.</para>
- </listitem>
- <listitem>
- <para>If an authentication attempt fails, the extension throws either a
- <classname>GuacamoleInsufficientCredentialsException</classname> (if more
- credentials are needed before validity can be determined) or
- <classname>GuacamoleInvalidCredentialsException</classname> (if the
- credentials are technically sufficient, but are invalid as provided). If all
- extensions fail to authenticate the user, the contents of the exception thrown
- by the first extension to fail are used to produce the user login prompt.</para>
- <para><emphasis>Note that this means there is no "login screen" in Guacamole per se;
- the prompt for credentials for unauthenticated users is determined purely
- based on the needs of the extension as declared within the authentication
- failure itself.</emphasis></para>
- <para>If an authentication attempt succeeds, the extension returns an instance of
- <classname>AuthenticatedUser</classname> describing the identity of the user
- that just authenticated, and no further extensions are polled.</para>
- </listitem>
- <listitem>
- <para>If authentication has succeeded, and thus an
- <classname>AuthenticatedUser</classname> is available, that
- <classname>AuthenticatedUser</classname> is passed to the
- <methodname>getUserContext()</methodname> function of all extensions'
- authentication providers. Each extension now has the opportunity to provide
- access to data for a user, even if that extension did not originally
- authenticate the user. If no <classname>UserContext</classname> is returned for
- the given <classname>AuthenticatedUser</classname>, then that extension has
- simply refused to provide data for that user.</para>
- <para>The Guacamole interface will transparently unify the data from each extension,
- providing the user with a view of all available connections. If the user has
- permission to modify or administer any objects associated with an extension,
- access to the administrative interface will be exposed as well, again with a
- unified view of all applicable objects.</para>
- </listitem>
- </orderedlist>
- <important>
- <para>Because authentication is decoupled from data storage/access, <emphasis>you do not
- need to implement full-blown data storage if you only wish to provide an
- additional authentication mechanism</emphasis>. You can instead implement only
- the authentication portion of an <classname>AuthenticationProvider</classname>, and
- otherwise rely on the storage and features provided by other extensions, such as the
- <link xmlns:xlink="http://www.w3.org/1999/xlink" linkend="jdbc-auth">database
- authentication extension</link>.</para>
- </important>
- <para>The Guacamole web application includes a basic authentication provider implementation
- which parses an XML file to determine which users exist, their corresponding passwords,
- and what configurations those users have access to. This is the part of Guacamole that
- reads the <filename>user-mapping.xml</filename> file. If you use a custom authentication
- provider for your authentication, this file will probably not be required.</para>
- <para>The community has implemented authentication providers which access databases, use
- LDAP, or even perform no authentication at all, redirecting all users to a single
- configuration specified in <filename>guacamole.properties</filename>.</para>
- <para>A minimal authentication provider is implemented in the tutorials later, and the
- upstream authentication provider implemented within Guacamole, as well as the
- authentication providers implemented by the community, are good examples for how
- authentication can be extended without having to implement a whole new web
- application.</para>
- <section xml:id="ext-simple-auth">
- <title><classname>SimpleAuthenticationProvider</classname></title>
- <para>The <classname>SimpleAuthenticationProvider</classname> class provides a much
- simpler means of implementing authentication when you do not require the ability to
- add and remove users and connections. It is an abstract class and requires only one
- function implementation:
- <methodname>getAuthorizedConfigurations()</methodname>.</para>
- <para>This function is required to return a <classname>Map</classname> of unique IDs to
- configurations, where these configurations are all configurations accessible with
- the provided credentials. As before, the credentials given are abstract. You are not
- required to use usernames and passwords.</para>
- <para>The configurations referred to by the function name are instances of
- <classname>GuacamoleConfiguration</classname> (part of guacamole-common), which
- is just a wrapper around a protocol name and set of parameter name/value pairs. The
- name of the protocol to use and a set of parameters is the minimum information
- required for other parts of the Guacamole API to complete the handshake required by
- the Guacamole protocol.</para>
- <para>When a class that extends <classname>SimpleAuthenticationProvider</classname> is
- asked for more advanced operations by the web application,
- <classname>SimpleAuthenticationProvider</classname> simply returns that there is
- no permission to do so. This effectively disables all administrative functionality
- within the web interface.</para>
- <para>If you choose to go the simple route, most of the rest of this chapter is
- irrelevant. Permissions, security model, and various classes will be discussed that
- are all handled for you automatically by
- <classname>SimpleAuthenticationProvider</classname>.</para>
- </section>
- </section>
- <section xml:id="ext-user-context">
- <title>The <classname>UserContext</classname></title>
- <para>The <classname>UserContext</classname> is the root of all data-related operations. It
- is used to list, create, modify, or delete users and connections, as well as to query
- available permissions. If an extension is going to provide access to data of any sort,
- it must do so through the <classname>UserContext</classname>.</para>
- <para>The Guacamole web application uses permissions queries against the
- <classname>UserContext</classname> to determine what operations to present, but
- <emphasis>beware that it is up to the <classname>UserContext</classname> to actually
- enforce these restrictions</emphasis>. The Guacamole web application will not
- enforce restrictions on behalf of the <classname>UserContext</classname>.</para>
- <para>The <classname>UserContext</classname> is the sole means of entry and the sole means
- of modification available to a logged-in user. If the <classname>UserContext</classname>
- refuses to perform an operation (by throwing an exception), the user cannot perform the
- operation at all.</para>
- </section>
- <section xml:id="ext-object-directories">
- <title><classname>Directory</classname> classes</title>
- <para>Access to objects beneath the <classname>UserContext</classname> is given through
- <classname>Directory</classname> classes. These <classname>Directory</classname>
- classes are similar to Java collections, but they also embody update and batching
- semantics. Objects can be retrieved from a <classname>Directory</classname> using its
- <methodname>get()</methodname> function and added or removed with
- <methodname>add()</methodname> and <methodname>remove()</methodname> respectively,
- but objects already in the set can also be updated by passing an updated object to its
- <methodname>update()</methodname> function.</para>
- <para>An implementation of a <classname>Directory</classname> can rely on these functions to
- define the semantics surrounding all operations. The <methodname>add()</methodname>
- function is called only when creating new objects, the <methodname>update()</methodname>
- function is called only when updating an object previously retrieved with
- <methodname>get()</methodname>, and <methodname>remove()</methodname> is called only
- when removing an existing object by its identifier.</para>
- <para>When implementing an <classname>AuthenticationProvider</classname>, you must ensure
- that the <classname>UserContext</classname> will only return
- <classname>Directory</classname> classes that automatically enforce the permissions
- associated with all objects and the associated user.</para>
- </section>
- <section xml:id="ext-rest-resources">
- <title>REST resources</title>
- <para>Arbitrary REST resources may be exposed by extensions at the
- <classname>AuthenticationProvider</classname> level, if the resource does not
- require an associated authenticated user, or at the <classname>UserContext</classname>
- level, if the resource should be available to authenticated users only. In both cases,
- the REST resource is provided through implementing the
- <function>getResource()</function> function, returning an object which is annotated
- with JAX-RS annotations (JSR 311).</para>
- <para>The resource returned by <function>getResource()</function> functions as the root
- resource, providing access to other resources beneath itself. The root resource for the
- <classname>AuthenticationProvider</classname> is exposed at
- <uri><replaceable>PATH</replaceable>/api/ext/<replaceable>IDENTIFIER</replaceable></uri>,
- and the root resource for the <classname>UserContext</classname> is exposed at
- <uri><replaceable>PATH</replaceable>/api/session/ext/<replaceable>IDENTIFIER</replaceable></uri>,
- where <replaceable>PATH</replaceable> is the path to which Guacamole has been deployed
- (typically <uri>/guacamole/</uri>) and <replaceable>IDENTIFIER</replaceable> is the
- unique identifier for the <classname>AuthenticationProvider</classname>, as returned by
- <function>getIdentifier()</function>.</para>
- <para>The behavior of extension REST resources is generally left entirely to the
- implementation, with the exception that the "token" request parameter is reserved for
- use by Guacamole. This parameter contains the user's authentication token when the user
- is logged in, and must be present on all requests which require authentication. Though
- not relevant to REST resources exposed at the
- <classname>AuthenticationProvider</classname> level, resources exposed at the
- <classname>UserContext</classname> level inherently require the "token" parameter to
- be present, as it is the sole means of locating the user's session.</para>
- </section>
- <section xml:id="ext-permissions">
- <title>Permissions</title>
- <para>The permissions system within guacamole-ext is an advisory system. It is the means by
- which an authentication module describes to the web application what a user is allowed
- to do. The body of permissions granted to a user describes which objects that user can
- see and what they can do to those objects, and thus suggests how the Guacamole interface
- should appear to that user.</para>
- <para><emphasis>Permissions are not the means by which access is restricted</emphasis>; they
- are purely a means of describing access level. An implementation may internally use the
- permission objects to define restrictions, but this is not required. It is up to the
- implementation to enforce its own restrictions by throwing exceptions when an operation
- is not allowed, and to correctly communicate the abilities of individual users through
- these permissions.</para>
- <para>The permissions available to a user are exposed through the
- <classname>SystemPermissionSet</classname> and
- <classname>ObjectPermissionSet</classname> classes which are accessible through the
- <classname>UserContext</classname>. These classes also serve as the means for
- manipulating the permissions granted to a user.</para>
- <section>
- <title xml:id="ext-system-permissions">System permissions</title>
- <para>System permissions describe access to operations that manipulate the system as a
- whole, rather than specific objects. This includes the creation of new objects, as
- object creation directly affects the system, and per-object controls cannot exist
- before the object is actually created.</para>
- <variablelist>
- <varlistentry>
- <term><constant>ADMINISTER</constant></term>
- <listitem>
- <para>The user is a super-user - the Guacamole equivalent of root. They are
- allowed to manipulate of system-level permissions and all other objects.
- This permission implies all others.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>CREATE_CONNECTION</constant></term>
- <listitem>
- <para>The user is allowed to create new connections. If a user has this
- permission, the management interface will display components related to
- connection creation.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>CREATE_CONNECTION_GROUP</constant></term>
- <listitem>
- <para>The user is allowed to create new connection groups. If a user has
- this permission, the management interface will display components
- related to connection group creation.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>CREATE_SHARING_PROFILE</constant></term>
- <listitem>
- <para>The user is allowed to create new sharing profiles. If a user has this
- permission, the management interface will display components related to
- sharing profile creation.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>CREATE_USER</constant></term>
- <listitem>
- <para>The user is allowed to create other users. If a user has this
- permission, the management interface will display components related to
- user creation.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section>
- <title xml:id="ext-object-permissions">Object permissions</title>
- <para>Object permissions describe access to operations that affect a particular object.
- Guacamole currently defines four types of objects which can be associated with
- permissions: users, connections, connection groups, and sharing profiles. Each
- object permission associates a single user with an action that may be performed on a
- single object.</para>
- <variablelist>
- <varlistentry>
- <term><constant>ADMINISTER</constant></term>
- <listitem>
- <para>The user may grant or revoke permissions involving this object.
- "Involving", in this case, refers to either side of the permission
- association, and includes both the user to whom the permission is
- granted and the object the permission affects.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>DELETE</constant></term>
- <listitem>
- <para>The user may delete this object. This is distinct from the
- <constant>ADMINISTER</constant> permission which deals only with
- permissions. A user with this permission will see the "Delete" button
- when applicable.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>READ</constant></term>
- <listitem>
- <para>The user may see that this object exists and read the properties of
- that object.</para>
- <para>Note that the implementation is <emphasis>not required to divulge the
- true underlying properties of any object</emphasis>. The parameters
- of a connection or sharing profile, the type or contents of a connection
- group, the password of a user, etc. all need not be exposed.</para>
- <para>This is particularly important from the perspective of security when
- it comes to connections, as the parameters of a connection are only
- truly needed when a connection is being modified, and likely should not
- be exposed otherwise. The actual connection operation is always
- performed internally by the authentication provider, and thus does not
- require client-side knowledge of anything beyond the connection's
- existence.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>UPDATE</constant></term>
- <listitem>
- <para>The user may change the properties of this object.</para>
- <para>In the case of users, this means the user's password can be altered.
- <emphasis>Permissions are not considered properties of a
- user</emphasis>, nor objects in their own right, but rather
- associations between a user and an action which may involve another
- object.</para>
- <para>The properties of a connection include its name, protocol, parent
- connection group, and parameters. The properties of a connection group
- include its name, type, parent connection group, and children. The
- properties of a sharing profile include its name, primary connection,
- and parameters.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </section>
- <section xml:id="ext-connections">
- <title>Connections</title>
- <para>Guacamole connections are organized in a hierarchy made up of connection groups, which
- each act as folders organizing the connections themselves. The hierarchy is accessed
- through the root-level connection group, exposed by
- <methodname>getRootConnectionGroup()</methodname> by the
- <classname>UserContext</classname>. The connections and connection groups exposed
- beneath the root connection group must also be accessible directly through the
- connection and connection group directories exposed by
- <methodname>getConnectionDirectory()</methodname> and
- <methodname>getConnectionGroupDirectory()</methodname> of the
- <classname>UserContext</classname>.</para>
- <para>When a user attempts to use a connection the <methodname>connect()</methodname> of the
- associated <classname>Connection</classname> object will be invoked. It is then up to
- the implementation of this function to establish the TCP connection to guacd, perform
- the connection handshake (most likely via an <classname>InetGuacamoleSocket</classname>
- wrapped within a <classname>ConfiguredGuacamoleSocket</classname>), and then return a
- <classname>GuacamoleTunnel</classname> which controls access to the established
- socket.</para>
- <para>Extensions may maintain historical record of connection use via
- <classname>ConnectionRecord</classname> objects, which are exposed both at the
- <classname>Connection</classname> level and across all connections via the
- <classname>UserContext</classname>. Such record maintenance is optional, and it is
- expected that most implementations will simply return empty lists.</para>
- <important>
- <para>If connection state will not be tracked by the extension, and the parameters
- associated with the connection will be known at the time the connection object is
- created, the <classname>SimpleConnection</classname> implementation of
- <classname>Connection</classname> can be used to make life easier.</para>
- </important>
- </section>
- <section xml:id="ext-active-connections">
- <title>Managing/sharing active connections</title>
- <para>After a connection has been established, its underlying
- <classname>GuacamoleTunnel</classname> can be exposed by a
- <classname>UserContext</classname> through the <classname>Directory</classname>
- returned by <methodname>getActiveConnectionDirectory()</methodname>. The
- <classname>ActiveConnection</classname> objects accessible through this
- <classname>Directory</classname> are the means by which an administrator may monitor
- or forcibly terminate another user's connection, ultimately resulting in Guacamole
- invoking the <methodname>close()</methodname> function of the underlying
- <classname>GuacamoleTunnel</classname>, and also serve as the basis for screen
- sharing.</para>
- <para>Screen sharing is implemented through the use of <classname>SharingProfile</classname>
- objects, exposed through yet another <classname>Directory</classname> beneath the
- <classname>UserContext</classname>. Each sharing profile is associated with a single
- connection that it can be used to share, referred to as the "primary connection". If a
- user has read access to a sharing profile associated with their current connection, that
- sharing profile will be displayed as an option within <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="client-share-menu">the share
- menu of the Guacamole menu</link>.</para>
- <para>The overall sharing process is as follows:</para>
- <orderedlist>
- <listitem>
- <para>A user, having access to a sharing profile associated with their current
- active connection, clicks its option within the <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="client-share-menu">share
- menu</link>.</para>
- </listitem>
- <listitem>
- <para>Guacamole locates the <classname>ActiveConnection</classname> and invokes its
- <methodname>getSharingCredentials()</methodname> function with the
- identifier of the sharing profile. The contents of the returned
- <classname>UserCredentials</classname> object is used by Guacamole to
- generate a sharing link which can be given to other users.</para>
- </listitem>
- <listitem>
- <para>When another user visits the sharing link, the credentials embedded in the
- link are passed to the authentication providers associated with each installed
- extension. <emphasis>It is up to the extension that originally provided those
- credentials to authenticate the user and provide them with access to the
- shared connection.</emphasis></para>
- </listitem>
- <listitem>
- <para>When the user attempts to connect to the shared connection, the extension
- establishes the connection using the ID of the connection being joined.
- <emphasis>This is not the connection identifier as dictated by
- guacamole-ext, but rather <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-protocol-joining">the unique ID assigned by guacd as
- required by the Guacamole protocol</link>.</emphasis> This ID can be
- retrieved from a <methodname>ConfiguredGuacamoleSocket</methodname> via
- <methodname>getConnectionID()</methodname>, and can be passed through a
- <methodname>GuacamoleConfiguration</methodname> through
- <methodname>setConnectionID()</methodname> (instead of specifying a
- protocol, as would be done for a brand new connection).</para>
- </listitem>
- </orderedlist>
- </section>
-</chapter>
diff --git a/src/chapters/header-auth.xml b/src/chapters/header-auth.xml
deleted file mode 100644
index 16a5a36..0000000
--- a/src/chapters/header-auth.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="header-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>HTTP header authentication</title>
- <indexterm>
- <primary>HTTP header authentication</primary>
- </indexterm>
- <para>Guacamole supports delegating authentication to an arbitrary external service, relying on
- the presence of an HTTP header which contains the username of the authenticated user. This
- authentication method must be layered on top of some other authentication extension, such as
- those available from the main project website, in order to provide access to actual
- connections.</para>
- <important>
- <para>All external requests must be properly sanitized if this extension is used. The chosen
- HTTP header must be stripped from untrusted requests, such that the authentication
- service is the only possible source of that header. <emphasis>If such sanitization is
- not performed, it will be trivial for malicious users to add this header manually,
- and thus gain unrestricted access.</emphasis></para>
- </important>
- <section xml:id="header-downloading">
- <title>Downloading the HTTP header authentication extension</title>
- <para>The HTTP header authentication extension is available separately from the main
- <filename>guacamole.war</filename>. The link for this and all other
- officially-supported and compatible extensions for a particular version of Guacamole are
- provided on the release notes for that version. You can find the release notes for
- current versions of Guacamole here: <link
- xlink:href="http://guacamole.apache.org/releases/"
- >http://guacamole.apache.org/releases/</link>.</para>
- <para>The HTTP header authentication extension is packaged as a <filename>.tar.gz</filename>
- file containing only the extension itself,
- <filename>guacamole-auth-header-1.2.0.jar</filename>, which must
- ultimately be placed in <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </section>
- <section xml:id="installing-header-auth">
- <title>Installing HTTP header authentication</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- located within the <filename>GUACAMOLE_HOME/extensions</filename> directory.
- <emphasis>If you are unsure where <varname>GUACAMOLE_HOME</varname> is located on
- your system, please consult <xref linkend="configuring-guacamole"/> before
- proceeding.</emphasis></para>
- <para>To install the HTTP header authentication extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Copy <filename>guacamole-auth-header-1.2.0.jar</filename> within
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </step>
- <step>
- <para>Configure Guacamole to use HTTP header authentication, as described
- below.</para>
- </step>
- </procedure>
- <section xml:id="guac-header-config">
- <title>Configuring Guacamole for HTTP header authentication</title>
- <indexterm>
- <primary>configuring HTTP header authentication</primary>
- </indexterm>
- <indexterm>
- <primary>HTTP header authentication</primary>
- <secondary>configuration</secondary>
- </indexterm>
- <para>The HTTP header authentication extension provides only one configuration property,
- and it is optional. By default, the extension will pull the username of the
- authenticated user from the <constant>REMOTE_USER</constant> header, if present. If
- your authentication system uses a different HTTP header, you will need to override
- this by specifying the <property>http-auth-header</property> property within <link
- linkend="initial-setup"><filename>guacamole.properties</filename></link>:</para>
- <variablelist>
- <varlistentry>
- <term><property>http-auth-header</property></term>
- <listitem>
- <para>The HTTP header containing the username of the authenticated user.
- This property is optional. If not specified,
- <constant>REMOTE_USER</constant> will be used by default.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="completing-header-install">
- <title>Completing the installation</title>
- <para>Guacamole will only reread <filename>guacamole.properties</filename> and load
- newly-installed extensions during startup, so your servlet container will need to be
- restarted before HTTP header authentication can be used. <emphasis>Doing this will
- disconnect all active users, so be sure that it is safe to do so prior to
- attempting installation.</emphasis> When ready, restart your servlet container
- and give the new authentication a try.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/hooks.xml b/src/chapters/hooks.xml
deleted file mode 100644
index d570879..0000000
--- a/src/chapters/hooks.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="events-hooks"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
-
- <title>Event handlers</title>
-
-</chapter>
diff --git a/src/chapters/installing.xml b/src/chapters/installing.xml
deleted file mode 100644
index 92bf162..0000000
--- a/src/chapters/installing.xml
+++ /dev/null
@@ -1,1034 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="installing-guacamole" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Installing Guacamole natively</title>
- <indexterm>
- <primary>installing</primary>
- </indexterm>
- <indexterm>
- <primary>compiling</primary>
- <secondary>Guacamole</secondary>
- </indexterm>
- <para>Guacamole is separated into two pieces: <package>guacamole-server</package>, which
- provides the <package>guacd</package> proxy and related libraries, and
- <package>guacamole-client</package>, which provides the client to be served by your
- servlet container, usually <link xl:href="http://tomcat.apache.org/">Tomcat</link>.</para>
- <para><package>guacamole-client</package> is available in binary form, but
- <package>guacamole-server</package> must be built from source. Don't be discouraged:
- building the components of Guacamole from source is <emphasis>not</emphasis> as difficult as
- it sounds, and the build process is automated. You just need to be sure you have the
- necessary tools installed ahead of time. With the necessary dependencies in place, building
- Guacamole only takes a few minutes.</para>
- <section xml:id="building-guacamole-server">
- <title>Building <package>guacamole-server</package></title>
- <indexterm>
- <primary><package>libguac</package></primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary>guacd</primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary>VNC support</primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary>RDP support</primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary>SSH support</primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary>telnet support</primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary><package>libguac-client-vnc</package></primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary><package>libguac-client-rdp</package></primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary><package>libguac-client-ssh</package></primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary><package>libguac-client-telnet</package></primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary><package>libguac-client-kubernetes</package></primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary><package>guacamole-server</package></primary>
- <secondary>compiling</secondary>
- </indexterm>
- <para><package>guacamole-server</package> contains all the native, server-side components
- required by Guacamole to connect to remote desktops. It provides a common C library,
- <package>libguac</package>, which all other native components depend on, as well as
- separate libraries for each supported protocol, and <package>guacd</package>, the heart
- of Guacamole.</para>
- <para><package>guacd</package> is the proxy daemon that runs on your Guacamole server,
- accepts users' connections that are tunneled through the Guacamole web application, and
- then connects to remote desktops on their behalf. Building <package>guacd</package>
- creates an executable called <filename>guacd</filename> which can be run manually or, if
- you wish, automatically when your computer starts up.</para>
- <para>To build <package>guacamole-server</package>, you will need a C compiler (such as
- <package>gcc</package>) and the libraries that <package>guacamole-server</package>
- depends on. Some dependencies are absolutely required, while others are optional. The
- presence of optional dependencies enables additional features.</para>
- <important>
- <para>Many Linux distributions separate library packages into binary and "development"
- packages; <emphasis>you will need to install the development packages</emphasis>.
- These will usually end in a "-dev" or "-devel" suffix.</para>
- </important>
- <section xml:id="required-dependencies">
- <title>Required dependencies</title>
- <para>In order to build <package>guacamole-server</package>, you will need
- <package>Cairo</package>, <package>libjpeg</package>, <package>libpng</package>,
- and the OSSP UUID library. These libraries are strictly required <emphasis>in all
- cases</emphasis> - Guacamole cannot be built without them.</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="lib-name" colnum="1" colwidth="1*"/>
- <colspec colname="features" colnum="2" colwidth="3.8*"/>
- <thead>
- <row>
- <entry>Library name</entry>
- <entry>Features</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><link xl:href="http://cairographics.org/">Cairo</link></entry>
- <entry>
- <para>Cairo is used by libguac for graphics rendering. Guacamole
- cannot function without Cairo installed.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libcairo2-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>cairo-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="http://libjpeg-turbo.virtualgl.org/"
- >libjpeg-turbo</link></entry>
- <entry>
- <para>libjpeg-turbo is used by libguac to provide JPEG support.
- Guacamole will not build without this library present:</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian package</entry>
- <entry><package>libjpeg62-turbo-dev</package></entry>
- </row>
- <row>
- <entry>Ubuntu package</entry>
- <entry><package>libjpeg-turbo8-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libjpeg-turbo-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>If libjpeg-turbo is unavailable on your platform, and you do
- not wish to build it from source, <link
- xl:href="http://www.ijg.org/">libjpeg</link> will work as
- well, though it will not be quite as fast:</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libjpeg62-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libjpeg-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="http://www.libpng.org/pub/png/libpng.html"
- >libpng</link></entry>
- <entry>
- <para>libpng is used by libguac to write PNG images, the core image
- type used by the Guacamole protocol. Guacamole cannot function
- without libpng.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libpng12-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libpng-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="https://www.gnu.org/software/libtool/manual/libtool.html"
- >libtool</link></entry>
- <entry>
- <para>libtool is used during the build process.
- libtool creates compiled libraries needed for Guacamole.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libtool-bin</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libtool</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry>libuuid (part of <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://www.kernel.org/pub/linux/utils/util-linux/"
- >util-linux</link>)</entry>
- <entry>
- <para>libuuid is used by libguac to assign unique, internal IDs to
- each Guacamole user and connection. These unique IDs are the
- basis for connection sharing support.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>uuid-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libuuid-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>If libuuid is unavailable, the <link
- xl:href="http://www.ossp.org/pkg/lib/uuid/">OSSP UUID</link>
- library may also be used:</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libossp-uuid-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>uuid-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="optional-dependencies">
- <title>Optional dependencies</title>
- <para>The optional dependencies of Guacamole dictate which parts of
- <package>guacamole-server</package> will be built. This includes the support for
- various remote desktop protocols, as well as any additional features of those
- protocols:</para>
- <itemizedlist>
- <listitem>
- <para>VNC support depends on the <package>libvncclient</package> library, which
- is part of <package>libVNCServer</package>.</para>
- </listitem>
- <listitem>
- <para>RDP support depends on a recent version of <package>FreeRDP</package> (1.0
- or higher, but please <link
- xl:href="https://github.com/FreeRDP/FreeRDP/issues/2839">not a
- non-release version from git</link>).</para>
- </listitem>
- <listitem>
- <para>SSH support depends on <package>libssh2</package>, <package>OpenSSL</package>
- and <package>Pango</package> (a font rendering and text layout library, used
- by Guacamole's built-in terminal emulator).</para>
- </listitem>
- <listitem>
- <para>Telnet depends on <package>libtelnet</package> and
- <package>Pango</package>.</para>
- </listitem>
- <listitem>
- <para>Kubernetes support depends on <package>libwebsockets</package>,
- <package>OpenSSL</package>, and <package>Pango</package>.</para>
- </listitem>
- </itemizedlist>
- <para>The <command>guacenc</command> utility, provided by
- <package>guacamole-server</package> to translate screen recordings into video,
- depends on FFmpeg, and will only be built if at least the
- <package>libavcodec</package>, <package>libavformat</package>,
- <package>libavutil</package>, and <package>libswscale</package> libraries
- provided by FFmpeg are installed.</para>
- <important>
- <para>If you lack these dependencies, <emphasis>then the features or protocols which
- depend on them will not be enabled</emphasis>. Please read this section
- carefully before deciding not to install an optional dependency.</para>
- </important>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="lib-name" colnum="1" colwidth="1*"/>
- <colspec colname="features" colnum="2" colwidth="3.8*"/>
- <thead>
- <row>
- <entry>Library name</entry>
- <entry>Features</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><link xl:href="https://ffmpeg.org/">FFmpeg</link></entry>
- <entry>
- <para>The <package>libavcodec</package>,
- <package>libavformat</package>,
- <package>libavutil</package>, and <package>libswscale</package>
- libraries provided by FFmpeg are used by
- <command>guacenc</command> to encode video streams when
- translating recordings of Guacamole sessions. Without FFmpeg,
- the <command>guacenc</command> utility will simply not be
- built.</para>
- <para>If you do not wish to make graphical recordings of Guacamole
- sessions, or do not wish to translate such recordings into
- video, then FFmpeg is not needed.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry>
- <para><package>libavcodec-dev</package>,
- <package>libavformat-dev</package>,
- <package>libavutil-dev</package>,
- <package>libswscale-dev</package></para>
- </entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>ffmpeg-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="http://www.freerdp.com/">FreeRDP</link></entry>
- <entry>
- <para>FreeRDP 2.0.0 or later is required for RDP support. If you do
- not wish to build RDP support, this library is not
- needed.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>freerdp2-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>freerdp-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="http://www.pango.org/">Pango</link></entry>
- <entry>
- <para>Pango is a text layout library which Guacamole uses to render
- text for protocols that require a terminal (Kubernetes, SSH, and
- telnet). If you do not wish to build any terminal-based protocol
- support, this library is not needed.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libpango1.0-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>pango-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="http://www.libssh2.org/">libssh2</link></entry>
- <entry>
- <para>libssh2 is required for SSH support. If you do not wish to
- build SSH support, this library is not needed.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libssh2-1-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libssh2-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="https://github.com/seanmiddleditch/libtelnet"
- >libtelnet</link></entry>
- <entry>
- <para>libtelnet is required for telnet support. If you do not wish
- to build telnet support, this library is not needed.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libtelnet-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libtelnet-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="http://libvnc.github.io/"
- >libVNCServer</link></entry>
- <entry>
- <para>libVNCServer provides libvncclient, which is required for VNC
- support. If you do not wish to build VNC support, this library
- is not needed.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libvncserver-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libvncserver-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="https://libwebsockets.org/">libwebsockets</link></entry>
- <entry>
- <para>libwebsockets is required for Kubernetes support. If you do
- not wish to build Kubernetes support, this library is not
- needed.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libwebsockets-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libwebsockets-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link
- xl:href="http://www.freedesktop.org/wiki/Software/PulseAudio/"
- >PulseAudio</link></entry>
- <entry>
- <para>PulseAudio provides libpulse, which is used by Guacamole's VNC
- support to provide experimental audio support. If you are not
- going to be using the experimental audio support for VNC, you do
- not need this library.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libpulse-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>pulseaudio-libs-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="https://www.openssl.org/">OpenSSL</link></entry>
- <entry>
- <para>OpenSSL provides support for SSL and TLS - two common
- encryption schemes that make up the majority of encrypted web
- traffic.</para>
- <para>If you have libssl installed, guacd will be built with SSL
- support, allowing communication between the web application and
- guacd to be encrypted. This library is also required for SSH
- support, for manipulating public/private keys, and for
- Kubernetes support, for SSL/TLS connections to the Kubernetes
- server.</para>
- <para>Without SSL support, there will be no option to encrypt
- communication to guacd, and support for SSH and Kubernetes
- cannot be built.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libssl-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>openssl-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="http://xiph.org/vorbis/">libvorbis</link></entry>
- <entry>
- <para>libvorbis provides support for Ogg Vorbis - a free and open
- standard for sound compression. If installed, libguac will be
- built with support for Ogg Vorbis, and protocols supporting
- audio will use Ogg Vorbis compression when possible.</para>
- <para>Otherwise, sound will only be encoded as WAV (uncompressed),
- and will only be available if your browser also supports
- WAV.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libvorbis-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libvorbis-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- <row>
- <entry><link xl:href="https://developers.google.com/speed/webp/"
- >libwebp</link></entry>
- <entry>
- <para>libwebp is used by libguac to write WebP images. Though
- support for WebP is not mandated by the Guacamole protocol, WebP
- images will be used if supported by both the browser and by
- libguac.</para>
- <para>Lacking WebP support, Guacamole will simply use JPEG in cases
- that it would have preferred WebP.</para>
- <informaltable frame="none" rowheader="firstcol">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <tbody>
- <row>
- <entry>Debian / Ubuntu package</entry>
- <entry><package>libwebp-dev</package></entry>
- </row>
- <row>
- <entry>Fedora / CentOS / RHEL package</entry>
- <entry><package>libwebp-devel</package></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section xml:id="guacamole-server-source">
- <title>Obtaining the source code</title>
- <para>You can obtain a copy of the <package>guacamole-server</package> source from the
- Guacamole project web site. These releases are stable snapshots of the latest code
- which have undergone enough testing that the Guacamole team considers them fit for
- public consumption. Source downloaded from the project web site will take the form
- of a <filename>.tar.gz</filename> archive which you can extract from the command
- line:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>tar -xzf guacamole-server-1.3.0.tar.gz</userinput>
-<prompt>$</prompt> <userinput>cd guacamole-server-1.3.0/</userinput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>If you want the absolute latest code, and don't care that the code hasn't been as
- rigorously tested as the code in stable releases, you can also clone the Guacamole
- team's git repository on GitHub:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>git clone <uri>git://github.com/apache/guacamole-server.git</uri></userinput>
-<computeroutput>Cloning into 'guacamole-server'...
-remote: Counting objects: 6769, done.
-remote: Compressing objects: 100% (2244/2244), done.
-remote: Total 6769 (delta 3058), reused 6718 (delta 3008)
-Receiving objects: 100% (6769/6769), 2.32 MiB | 777 KiB/s, done.
-Resolving deltas: 100% (3058/3058), done.</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- </section>
- <section xml:id="guacamole-server-build-process">
- <title>The build process</title>
- <para>Once the <package>guacamole-server</package> source has been downloaded and
- extracted, you need to run <filename>configure</filename>. This is a shell script
- automatically generated by GNU Autotools, a popular build system used by the
- Guacamole project for <package>guacamole-server</package>. Running
- <filename>configure</filename> will determine which libraries are available on
- your system and will select the appropriate components for building depending on
- what you actually have installed.</para>
- <important>
- <para>Source downloaded directly from git will not contain this
- <filename>configure</filename> script, as autogenerated code is not included
- in the project's repositories. If you downloaded the code from the project's git
- repositories directly, you will need to generate <filename>configure</filename>
- manually:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>cd guacamole-server/</userinput>
-<prompt>$</prompt> <userinput>autoreconf -fi</userinput>
-<prompt>$</prompt></screen>
- <para>Doing this requires GNU Autotools to be installed.</para>
- <para>Source archives downloaded from the project website contain the
- <filename>configure</filename> script and all other necessary build
- files, and thus do not require GNU Autotools to be installed on the build
- machine.</para>
- </informalexample>
- </important>
- <para>Once you run <filename>configure</filename>, you can see what a listing of what
- libraries were found and what it has determined should be built:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>./configure --with-init-dir=<replaceable>/etc/init.d</replaceable></userinput>
-<computeroutput>checking for a BSD-compatible install... /usr/bin/install -c
-checking whether build environment is sane... yes
-...
-
-------------------------------------------------
-guacamole-server version 1.3.0
-------------------------------------------------
-
- Library status:
-
- freerdp2 ............ yes
- pango ............... yes
- libavcodec .......... yes
- libavformat ......... yes
- libavutil ........... yes
- libssh2 ............. yes
- libssl .............. yes
- libswscale .......... yes
- libtelnet ........... yes
- libVNCServer ........ yes
- libvorbis ........... yes
- libpulse ............ yes
- libwebsockets ....... yes
- libwebp ............. yes
- wsock32 ............. no
-
- Protocol support:
-
- Kubernetes .... yes
- RDP ........... yes
- SSH ........... yes
- Telnet ........ yes
- VNC ........... yes
-
- Services / tools:
-
- guacd ...... yes
- guacenc .... yes
- guaclog .... yes
-
- Init scripts: /etc/init.d
- Systemd units: no
-
-Type "make" to compile guacamole-server.
-</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para><indexterm>
- <primary><package>guacd</package></primary>
- <secondary>startup script</secondary>
- </indexterm>The <option>--with-init-dir=/etc/init.d</option> shown above prepares
- the build to install a startup script for <package>guacd</package> into the
- <filename>/etc/init.d</filename> directory, such that we can later easily
- configure <package>guacd</package> to start automatically on boot. If you do not
- wish guacd to start automatically at boot, leave off the
- <option>--with-init-dir</option> option. If the directory containing your
- distribution's startup scripts differs from the common
- <filename>/etc/init.d</filename>, replace <filename>/etc/init.d</filename> with
- the proper directory here. You may need to consult your distribution's
- documentation, or do a little digging in <filename>/etc</filename>, to determine the
- proper location.</para>
- <para>Here, <filename>configure</filename> has found everything, including all optional
- libraries, and will build all protocol support, even support for Ogg Vorbis sound in
- RDP. If you are missing some libraries, some of the
- "<computeroutput>yes</computeroutput>" answers above will read
- "<computeroutput>no</computeroutput>". If a library which is strictly required
- is missing, the script will fail outright, and you will need to install the missing
- dependency. If, after running <filename>configure</filename>, you find support for
- something you wanted is missing, simply install the corresponding dependencies and
- run <filename>configure</filename> again.</para>
- <important>
- <para>All protocols that require a terminal (Kubernetes, SSH, and telnet) require
- that fonts are installed on the Guacamole server in order to function, as output
- from the terminal cannot be rendered otherwise. Support for these protocols will
- build just fine if fonts are not installed, but it will fail to connect when
- used:</para>
- <informalexample>
- <screen>Aug 23 14:09:45 my-server guacd[5606]: Unable to get font "monospace"</screen>
- </informalexample>
- <para>If terminal-based connections are not working and you see such a message in
- syslog, you should make sure fonts are installed and try again.</para>
- </important>
- <para>Once <filename>configure</filename> is finished, just type
- "<userinput>make</userinput>", and it will <package>guacamole-server</package>
- will compile:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>make</userinput>
-<computeroutput>Making all in src/libguac
-make[1]: Entering directory `/home/zhz/guacamole/guacamole-server/src/libguac'
-...
-make[1]: Leaving directory `/home/zhz/guacamole/guacamole-server/src/protocols/vnc'
-make[1]: Entering directory `/home/zhz/guacamole/guacamole-server'
-make[1]: Nothing to be done for `all-am'.
-make[1]: Leaving directory `/home/zhz/guacamole/guacamole-server'</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>Quite a bit of output will scroll up the screen as all the components are
- compiled.</para>
- </section>
- <section xml:id="guacamole-server-installation">
- <title>Installation</title>
- <para>Once everything finishes, all you have left to do is type "<userinput>make
- install</userinput>" to install the components that were built, and then
- "<userinput>ldconfig</userinput>" to update your system's cache of installed
- libraries:</para>
- <informalexample>
- <screen><prompt>#</prompt> <userinput>make install</userinput>
-<computeroutput>Making install in src/libguac
-make[1]: Entering directory `/home/zhz/guacamole/guacamole-server/src/libguac'
-make[2]: Entering directory `/home/zhz/guacamole/guacamole-server/src/libguac'
-...
-----------------------------------------------------------------------
-Libraries have been installed in:
- /usr/local/lib
-
-If you ever happen to want to link against installed libraries
-in a given directory, LIBDIR, you must either use libtool, and
-specify the full pathname of the library, or use the `-LLIBDIR'
-flag during linking and do at least one of the following:
- - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
- during execution
- - add LIBDIR to the `LD_RUN_PATH' environment variable
- during linking
- - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
- - have your system administrator add LIBDIR to `/etc/ld.so.conf'
-
-See any operating system documentation about shared libraries for
-more information, such as the ld(1) and ld.so(8) manual pages.
-----------------------------------------------------------------------
-make[2]: Nothing to be done for `install-data-am'.
-make[2]: Leaving directory `/home/zhz/guacamole/guacamole-server/src/protocols/vnc'
-make[1]: Leaving directory `/home/zhz/guacamole/guacamole-server/src/protocols/vnc'
-make[1]: Entering directory `/home/zhz/guacamole/guacamole-server'
-make[2]: Entering directory `/home/zhz/guacamole/guacamole-server'
-make[2]: Nothing to be done for `install-exec-am'.
-make[2]: Nothing to be done for `install-data-am'.
-make[2]: Leaving directory `/home/zhz/guacamole/guacamole-server'
-make[1]: Leaving directory `/home/zhz/guacamole/guacamole-server'</computeroutput>
-<prompt>#</prompt> <userinput>ldconfig</userinput>
-<prompt>#</prompt> </screen>
- </informalexample>
- <para>At this point, everything is installed, but <package>guacd</package> is not
- running. You will need to run guacd in order to use Guacamole once the client
- components are installed as well.</para>
- <para>Beware that even after installing <package>guacd</package> and its startup script,
- you will likely still have to activate the service for it to start automatically.
- Doing this varies by distribution, but each distribution will have documentation
- describing how to do so.</para>
- </section>
- </section>
- <section xml:id="building-guacamole-client">
- <title><package>guacamole-client</package></title>
- <indexterm>
- <primary><filename>guacamole.war</filename></primary>
- <secondary>compiling</secondary>
- </indexterm>
- <indexterm>
- <primary><package>guacamole-client</package></primary>
- <secondary>compiling</secondary>
- </indexterm>
- <important>
- <para>Normally, you don't need to build <package>guacamole-client</package>, as it is
- written in Java and is cross-platform. You can easily obtain the latest version of
- <package>guacamole-client</package> from the release archives of the Guacamole
- project web site, including all supported extensions, without having to build it
- yourself.</para>
- <para>If you do not want to build guacamole-client from source, just download
- <filename>guacamole.war</filename> from the project web site, along with any
- desired extensions, and skip ahead to <xref linkend="deploying-guacamole"/>.</para>
- </important>
- <para><package>guacamole-client</package> contains all Java and JavaScript components of
- Guacamole (<package>guacamole</package>, <package>guacamole-common</package>,
- <package>guacamole-ext</package>, and <package>guacamole-common-js</package>). These
- components ultimately make up the web application that will serve the HTML5 Guacamole
- client to users that connect to your server. This web application will then connect to
- <package>guacd</package>, part of <package>guacamole-server</package>, on behalf of
- connected users in order to serve them any remote desktop they are authorized to
- access.</para>
- <para>To compile <package>guacamole-client</package>, all you need is Apache Maven and a
- copy of the Java JDK. Most, if not all, Linux distributions will provide packages for
- these.</para>
- <para>You can obtain a copy of the <package>guacamole-client</package> source from the
- Guacamole project web site. These releases are stable snapshots of the latest code which
- have undergone enough testing that the Guacamole team considers them fit for public
- consumption. Source downloaded from the project web site will take the form of a
- <filename>.tar.gz</filename> archive which you can extract from the command
- line:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>tar -xzf guacamole-client-1.3.0.tar.gz</userinput>
-<prompt>$</prompt> <userinput>cd guacamole-client-1.3.0/</userinput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>As with <package>guacamole-server</package>, if you want the absolute latest code, and
- don't care that the code hasn't been as rigorously tested as the code in stable
- releases, you can also clone the Guacamole team's git repository on GitHub:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>git clone <uri>git://github.com/apache/guacamole-client.git</uri></userinput>
-<computeroutput>Cloning into 'guacamole-client'...
-remote: Counting objects: 12788, done.
-remote: Compressing objects: 100% (4183/4183), done.
-remote: Total 12788 (delta 3942), reused 12667 (delta 3822)
-Receiving objects: 100% (12788/12788), 3.23 MiB | 799 KiB/s, done.
-Resolving deltas: 100% (3942/3942), done.</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>Unlike <package>guacamole-server</package>, even if you grab the code from the git
- repositories, you won't need to run anything before building. There are no scripts that
- need to be generated before building - all Maven needs is the
- <filename>pom.xml</filename> file provided with the source.</para>
- <para>To build <package>guacamole-client</package>, just run "<userinput>mvn
- package</userinput>". This will invoke Maven to automatically build and package all
- components, producing a single <filename>.war</filename> file, which contains the entire
- web application:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>mvn package</userinput>
-<computeroutput>[INFO] Scanning for projects...
-[INFO] ------------------------------------------------------------------------
-[INFO] Reactor Build Order:
-[INFO]
-[INFO] guacamole-common
-[INFO] guacamole-ext
-[INFO] guacamole-common-js
-[INFO] guacamole
-[INFO] guacamole-auth-cas
-[INFO] guacamole-auth-duo
-[INFO] guacamole-auth-header
-[INFO] guacamole-auth-jdbc
-[INFO] guacamole-auth-jdbc-base
-[INFO] guacamole-auth-jdbc-mysql
-[INFO] guacamole-auth-jdbc-postgresql
-[INFO] guacamole-auth-jdbc-sqlserver
-[INFO] guacamole-auth-jdbc-dist
-[INFO] guacamole-auth-ldap
-[INFO] guacamole-auth-openid
-[INFO] guacamole-auth-quickconnect
-[INFO] guacamole-auth-totp
-[INFO] guacamole-example
-[INFO] guacamole-playback-example
-[INFO] guacamole-client
-...
-[INFO] ------------------------------------------------------------------------
-[INFO] Reactor Summary:
-[INFO]
-[INFO] guacamole-common ................................... SUCCESS [ 21.852 s]
-[INFO] guacamole-ext ...................................... SUCCESS [ 9.055 s]
-[INFO] guacamole-common-js ................................ SUCCESS [ 1.988 s]
-[INFO] guacamole .......................................... SUCCESS [ 18.040 s]
-[INFO] guacamole-auth-cas ................................. SUCCESS [ 4.203 s]
-[INFO] guacamole-auth-duo ................................. SUCCESS [ 2.251 s]
-[INFO] guacamole-auth-header .............................. SUCCESS [ 1.399 s]
-[INFO] guacamole-auth-jdbc ................................ SUCCESS [ 1.396 s]
-[INFO] guacamole-auth-jdbc-base ........................... SUCCESS [ 3.266 s]
-[INFO] guacamole-auth-jdbc-mysql .......................... SUCCESS [ 4.665 s]
-[INFO] guacamole-auth-jdbc-postgresql ..................... SUCCESS [ 3.764 s]
-[INFO] guacamole-auth-jdbc-sqlserver ...................... SUCCESS [ 3.738 s]
-[INFO] guacamole-auth-jdbc-dist ........................... SUCCESS [ 1.214 s]
-[INFO] guacamole-auth-ldap ................................ SUCCESS [ 1.991 s]
-[INFO] guacamole-auth-openid .............................. SUCCESS [ 2.204 s]
-[INFO] guacamole-auth-quickconnect ........................ SUCCESS [ 2.983 s]
-[INFO] guacamole-auth-totp ................................ SUCCESS [ 8.154 s]
-[INFO] guacamole-example .................................. SUCCESS [ 0.895 s]
-[INFO] guacamole-playback-example ......................... SUCCESS [ 0.795 s]
-[INFO] guacamole-client ................................... SUCCESS [ 7.478 s]
-[INFO] ------------------------------------------------------------------------
-[INFO] BUILD SUCCESS
-[INFO] ------------------------------------------------------------------------
-[INFO] Total time: 01:41 min
-[INFO] Finished at: 2018-10-15T17:08:29-07:00
-[INFO] Final Memory: 42M/379M
-[INFO] ------------------------------------------------------------------------</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>Once the Guacamole web application is built, there will be a .war file in the
- <filename>guacamole/target/</filename> subdirectory of the current directory (the
- directory you were in when you ran <application>mvn</application>), ready to be deployed
- to a servlet container like Tomcat.</para>
- </section>
- <section xml:id="deploying-guacamole">
- <title>Deploying Guacamole</title>
- <indexterm>
- <primary>deploying</primary>
- </indexterm>
- <para>The web application portion of Guacamole is packaged as a fully self-contained
- <filename>.war</filename> file. If you downloaded Guacamole from the main project
- web site, this file will be called <filename>guacamole.war</filename>. Deploying this
- involves copying the file into the directory your servlet container uses for
- <filename>.war</filename> files. In the case of Tomcat, this will be
- <filename><replaceable>CATALINA_HOME</replaceable>/webapps/</filename>. The
- location of <envar>CATALINA_HOME</envar> will vary by how Tomcat was installed, but is
- commonly <filename>/var/lib/tomcat</filename>, <filename>/var/lib/tomcat7</filename>, or
- similar:</para>
- <informalexample>
- <screen><prompt>#</prompt> <userinput>cp guacamole.war <replaceable>/var/lib/tomcat</replaceable>/webapps</userinput>
-<prompt>#</prompt></screen>
- </informalexample>
- <para>If you have built guacamole-client from source, the required <filename>.war</filename>
- file will be within the <filename>guacamole/target/</filename> directory and will
- contain an additional version suffix. As Tomcat will determine the location of the web
- application from the name of the <filename>.war</filename> file, you will likely want to
- rename this to simply <filename>guacamole.war</filename> while copying:</para>
- <informalexample>
- <screen><prompt>#</prompt> <userinput>cp guacamole/target/guacamole-1.3.0.war <replaceable>/var/lib/tomcat/webapps</replaceable>/guacamole.war</userinput>
-<prompt>#</prompt></screen>
- </informalexample>
- <para>Again, if you are using a different servlet container or if Tomcat is installed to a
- different location, you will need to check the documentation of your servlet container,
- distribution, or both to determine the proper location for deploying
- <filename>.war</filename> files like <filename>guacamole.war</filename>.</para>
- <para>Once the <filename>.war</filename> file is in place, you may need to restart Tomcat to
- force Tomcat to deploy the new web application, and the <package>guacd</package> daemon
- must be started if it isn't running already. The command to restart Tomcat and
- <package>guacd</package> will vary by distribution. Typically, you can do this by
- running the corresponding init scripts with the "restart" option:</para>
- <informalexample>
- <screen><prompt>#</prompt> <userinput>/etc/init.d/tomcat7 restart</userinput>
-<computeroutput>Stopping Tomcat... OK
-Starting Tomcat... OK</computeroutput>
-<prompt>#</prompt> <userinput>/etc/init.d/guacd start</userinput>
-<computeroutput>Starting guacd: SUCCESS
-guacd[6229]: INFO: Guacamole proxy daemon (guacd) version 1.3.0 started</computeroutput>
-<prompt>#</prompt></screen>
- </informalexample>
- <important>
- <para>If you want Guacamole to start on boot, you will need to configure the Tomcat and
- <package>guacd</package> services to run automatically. Your distribution will
- provide documentation for doing this.</para>
- </important>
- <para>After restarting Tomcat and starting <package>guacd</package>, Guacamole is
- successfully installed, though it will not be fully running. In its current state, it is
- completely unconfigured, and further steps are required to add at least one Guacamole
- user and a few connections. This is covered in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="configuring-guacamole"/>.</para>
- <section>
- <title>What about WebSocket?</title>
- <indexterm>
- <primary>WebSocket</primary>
- </indexterm>
- <para>Guacamole will use WebSocket automatically if supported by the browser and your
- servlet container. In the event that Guacamole cannot connect using WebSocket, it
- will immediately and transparently fall back to using HTTP.</para>
- <para>WebSocket is supported in Guacamole for Tomcat 7.0.37 or higher, Jetty 8 or
- higher, and any servlet container supporting JSR 356, the standardized Java API for
- WebSocket.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/jdbc-auth.xml b/src/chapters/jdbc-auth.xml
deleted file mode 100644
index 869a52d..0000000
--- a/src/chapters/jdbc-auth.xml
+++ /dev/null
@@ -1,2369 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="jdbc-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>Database authentication</title>
- <indexterm>
- <primary>MySQL</primary>
- </indexterm>
- <indexterm>
- <primary>PostgreSQL</primary>
- </indexterm>
- <indexterm>
- <primary>load balancing</primary>
- </indexterm>
- <para>Guacamole supports authentication via MySQL, PostgreSQL, or SQL Server databases through
- extensions available from the project website. Using a database for authentication provides
- additional features, such as the ability to use load balancing groups of connections and a
- web-based administrative interface. Unlike the default, XML-driven authentication module, all
- changes to users and connections take effect immediately; users need not logout and back in
- to see new connections.</para>
- <para>While most authentication extensions function independently, the database authentication
- can act in a subordinate role, allowing users and user groups from other authentication
- extensions to be associated with connections within the database. Users and groups are
- considered identical to those within the database if they have the same names, and the
- authentication result of another extension will be trusted if it succeeds. A user with an
- account under multiple systems will thus be able to see data from each system after
- successfully logging in. For more information on using the database authentication alongside
- other mechanisms, see <xref linkend="ldap-and-database"/> within <xref linkend="ldap-auth"
- />.</para>
- <para>To use the database authentication extension, you will need:</para>
- <orderedlist>
- <listitem>
- <para>A supported database - currently MariaDB, MySQL, PostgreSQL, or SQL Server.</para>
- </listitem>
- <listitem>
- <para>Sufficient permission to create new databases, to create new users, and to grant
- those users permissions.</para>
- </listitem>
- <listitem>
- <para>Network access to the database from the Guacamole server.</para>
- </listitem>
- </orderedlist>
- <important>
- <para>This chapter involves modifying the contents of <varname>GUACAMOLE_HOME</varname> -
- the Guacamole configuration directory. If you are unsure where
- <varname>GUACAMOLE_HOME</varname> is located on your system, please consult <xref
- linkend="configuring-guacamole"/> before proceeding.</para>
- </important>
- <section>
- <title>Downloading the database authentication extension</title>
- <para>The database authentication extension is available separately from the main
- <filename>guacamole.war</filename>. The link for this and all other
- officially-supported and compatible extensions for a particular version of Guacamole are
- provided on the release notes for that version. You can find the release notes for
- current versions of Guacamole here: <link
- xlink:href="http://guacamole.apache.org/releases/"
- >http://guacamole.apache.org/releases/</link>.</para>
- <para>The database authentication extension is packaged as a <filename>.tar.gz</filename>
- file containing:</para>
- <variablelist>
- <varlistentry>
- <term><filename>mysql/</filename></term>
- <listitem>
- <para>Contains the MySQL/MariaDB authentication extension,
- <filename>guacamole-auth-jdbc-mysql-1.3.0.jar</filename>, along with a
- <filename>schema/</filename> directory containing MySQL-specific SQL
- scripts required to set up the database. The
- <filename>guacamole-auth-jdbc-mysql-1.3.0.jar</filename> file will
- ultimately need to be placed within
- <filename>GUACAMOLE_HOME/extensions</filename>, while the MySQL JDBC
- driver must be placed within <filename>GUACAMOLE_HOME/lib</filename>.</para>
- <para><emphasis>The MySQL JDBC driver is not included with the
- extension.</emphasis> You must obtain a supported JDBC driver
- <filename>.jar</filename> yourself. The MySQL driver can be downloaded
- from <link xlink:href="http://dev.mysql.com/downloads/connector/j/">MySQL's
- website</link>, and is known as "Connector/J". The required
- <filename>.jar</filename> will be within a <filename>.tar.gz</filename>
- archive.</para>
- <para>In addition to the parameters below that are common to all database
- extensions, the MySQL extension supports properties that configure behavior
- specific to MySQL-compatible servers.</para>
- <para>The <property>mysql-driver</property> property, which controls which JDBC
- driver the extension attempts to load and its compatibility with various
- target database implementations. The extension currently supports the
- following values for the <property>mysql-driver</property> property:
- <variablelist>
- <varlistentry>
- <term>mysql</term>
- <listitem>
- <para>The MySQL JDBC driver, known as Connector/J.
- This is the default.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>mariadb</term>
- <listitem>
- <para>The MariaDB JDBC driver.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
- <para>The <property>mysql-server-timezone</property> property allows you to
- to specify the timezone the MySQL server is configured to run in. While
- the MySQL driver attempts to auto-detect the timezone in use by the server,
- there are many cases where the timezone provided by the operating system
- is either unknown by Java, or matches multiple timezones. In these cases
- MySQL may either complain or refuse the connection unless the timezone
- is specified as part of the connection. This property allows the timezone
- of the server to be specified so that the connection can continue and
- the JDBC driver can properly translate timestamps. The property accepts
- timezones in the following formats:
- <variablelist>
- <varlistentry>
- <term>Region/Locale</term>
- <listitem>
- <para>Well-known TimeZone Identifiers, in the Region/Locale
- format. Examples are:
- <informalexample>
- <programlisting>mysql-server-timezone: America/Los_Angeles
-mysql-server-timezone: Africa/Johannesburg
-mysql-server-timezone: China/Shanghai</programlisting>
- </informalexample>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>GMT+/-HH:MM</term>
- <listitem>
- <para>GMT or custom timezones specified by GMT offset. Examples
- of valid GMT specifications are:
- <informalexample>
- <programlisting>mysql-server-timezone: GMT
-mysql-server-timezone: GMT-00:00
-mysql-server-timezone: GMT+0000
-mysql-server-timezone: GMT-0</programlisting>
- </informalexample>
- </para>
- <para>Examples of custom timezones specified by GMT offsets are:
- <informalexample>
- <programlisting>mysql-server-timezone: GMT+0130
-mysql-server-timezone: GMT-0430
-mysql-server-timezone: GMT+06:00
-mysql-server-timezone: GMT-9</programlisting>
- </informalexample>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
- <para>The MySQL Driver implements several parameters specific to configuring
- SSL for secure connections to MySQL servers that support or require
- encrypted communications. <emphasis>Older versions of MySQL Connector/J
- have known issues with SSL verification - if you experience problems
- connecting to SSL-secured MySQL databases it is recommended that
- you update to a current version of the driver.</emphasis></para>
- <para>Configuration parameters for MySQL-compatible SSL support are as
- follows:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Property</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><property>mysql-ssl-mode</property></entry>
- <entry>
- <para>This property sets the SSL mode that the JDBC
- driver will attempt to use when communicating
- with the remote MySQL server. The values for
- this property match the standard values supported
- by the MySQL and MariaDB JDBC drivers:</para>
- <variablelist>
- <varlistentry>
- <term>disabled</term>
- <listitem>
- <para>Do not use SSL, and fail if the
- server requires it. For compatibility
- this will also set the legacy JDBC
- driver property
- <property>useSSL</property> to false.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>preferred</term>
- <listitem>
- <para>Prefer SSL, but fall back to
- plain-text if an SSL connection
- cannot be negotiated. This
- is the default.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>required</term>
- <listitem>
- <para>Require SSL connections, and fail
- if SSL cannot be negotiated. This mode
- does not perform any validition checks
- on the certificate in use by the server,
- the issuer, etc.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>verify-ca</term>
- <listitem>
- <para>Require SSL connections, and check
- to make sure that the certificate issuer
- is known to be valid.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>verify-identity</term>
- <listitem>
- <para>Require SSL connections, and check
- to make sure that the server certificate
- is issued by a known authority, and that
- the identity of the server matches the
- identity on the certificate.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </entry>
- </row>
- <row>
- <entry><property>mysql-ssl-trust-store</property></entry>
- <entry>
- <para>The file that will store trusted SSL certificates
- for the JDBC driver to use when validating CA and
- server certificates. This should be a JKS-formatted
- certificate store. This property is optional and
- defaults to Java's normal trusted certificate
- locations, which vary based on the version of
- Java in use.</para>
- </entry>
- </row>
- <row>
- <entry><property>mysql-ssl-trust-password</property></entry>
- <entry>
- <para>The password to use to access the SSL trusted
- certificate store, if one is required. By default
- no password will be used.</para>
- </entry>
- </row>
- <row>
- <entry><property>mysql-ssl-client-store</property></entry>
- <entry>
- <para>The file that contains the client certificate to
- use when making SSL connections to the MySQL server.
- This should be a JKS-formatted certificate store that
- contains a private key and certificate pair. This
- property is optional, and by default no client
- certificate will be used for the SSL connection.</para>
- </entry>
- </row>
- <row>
- <entry><property>mysql-ssl-client-password</property></entry>
- <entry>
- <para>The password to use to access the client
- certificate store, if one is required. By default
- no password will be used.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>postgresql/</filename></term>
- <listitem>
- <para>Contains the PostgreSQL authentication extension,
- <filename>guacamole-auth-jdbc-postgresql-1.3.0.jar</filename>, along
- with a <filename>schema/</filename> directory containing PostgreSQL-specific
- SQL scripts required to set up the database. The
- <filename>guacamole-auth-jdbc-postgresql-1.3.0.jar</filename> file will
- ultimately need to be placed within
- <filename>GUACAMOLE_HOME/extensions</filename>, while the PostgreSQL
- JDBC driver must be placed within
- <filename>GUACAMOLE_HOME/lib</filename>.</para>
- <para><emphasis>The PostgreSQL JDBC driver is not included with the
- extension.</emphasis> You must obtain the JDBC driver
- <filename>.jar</filename> yourself from <link
- xlink:href="https://jdbc.postgresql.org/download.html#current"
- >PostgreSQL's website</link>. The proper <filename>.jar</filename> file
- depends on the version of Java you have installed. </para>
- <para>The PostgreSQL extension implements several parameters specific to
- conifiguring SSL for secure connections to Postgres servers that support
- or require encrypted communications. The parameters are as follows:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Property</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><property>postgresql-ssl-mode</property></entry>
- <entry>
- <para>This property sets the SSL mode that the JDBC
- extension will attempt to use when communicating
- with the remote Postgres server. The values for
- this property match the standard values supported
- by the Postgres JDBC driver:</para>
- <variablelist>
- <varlistentry>
- <term>disable</term>
- <listitem>
- <para>Do not use SSL, and fail if the
- server requires it.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>allow</term>
- <listitem>
- <para>If the server requires encryption
- use it, otherwise prefer unencrypted
- connections.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>prefer</term>
- <listitem>
- <para>Try SSL connections, first, but
- allow unencrypted connections if
- the server does not support SSL or
- if SSL negotiations fail. This is
- the default.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>require</term>
- <listitem>
- <para>Require SSL connections, but
- implicitly trust all server
- certificates and authoritiers.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>verify-ca</term>
- <listitem>
- <para>Require SSL connections, and
- verify that the server certificate
- is issued by a known certificate
- authority.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>verify-full</term>
- <listitem>
- <para>Require SSL connections,
- verifying that the server certificate
- is issued by a known authority, and
- that the name on the certificate
- matches the name of the server.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </entry>
- </row>
- <row>
- <entry><property>postgresql-ssl-cert-file</property></entry>
- <entry>
- <para>The file containing the client certificate
- to be used when making an SSL-encrtyped connection
- to the Postgres server, in PEM format. This
- property is optional, and will be ignored if the
- SSL mode is set to disable.</para>
- </entry>
- </row>
- <row>
- <entry><property>postgresql-ssl-key-file</property></entry>
- <entry>
- <para>The file containing the client private key
- to be used when making an SSL-encrypted connection
- to the Postgres server, in PEM format. This
- property is optional, and will be ignore if the
- SSL mode is set to disable.</para>
- </entry>
- </row>
- <row>
- <entry><property>postgresql-ssl-root-cert-file</property></entry>
- <entry>
- <para>The file containing the root and intermedidate
- certificates against which the server certificate
- will be verified when making an SSL-encrypted
- connection to the Postgres server. This file should
- contain one or more PEM-formatted authority
- certificates. This property is optional, and will
- only be used if SSL mode is set to verify-ca or
- verify-full.</para>
- <para>If SSL is set to one of the verification modes
- and this property is not specified, the JDBC driver
- will attempt to use the
- <filename>.postgresql/root.crt</filename> file
- from the home directory of the user running the
- web application server (e.g. Tomcat). If this
- property is not specified and the default file
- does not exist, the Postgres JDBC driver will
- fail to connect to the server.</para>
- </entry>
- </row>
- <row>
- <entry><property>postgresql-ssl-key-password</property></entry>
- <entry>
- <para>The password that will be used to access the
- client private key file, if the client private
- key is encrypted. This property is optional,
- and is only used if the
- <property>postgresql-ssl-key-file</property>
- property is set and SSL is enabled.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>The PostgreSQL extension also implements some parameters to
- configure timeouts at the database and network level.
- The parameters are as follows:</para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Property</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><property>postgresql-default-statement-timeout</property></entry>
- <entry>
- <para>The number of seconds the driver will wait for a
- response from the database, before aborting the query.
- A value of 0 (the default) means the timeout is disabled.</para>
- </entry>
- </row>
- <row>
- <entry><property>postgresql-socket-timeout</property></entry>
- <entry>
- <para>The number of seconds to wait for socket read
- operations. If reading from the server takes longer than
- this value, the connection will be closed. This can be used
- to handle network problems such as a dropped connection to
- the database. Similar to
- <property>postgresql-default-statement-timeout</property>,
- it will also abort queries that take too long. A value of 0
- (the default) means the timeout is disabled.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>sqlserver/</filename></term>
- <listitem>
- <para>Contains the SQL Server authentication extension,
- <filename>guacamole-auth-jdbc-sqlserver-1.3.0.jar</filename>, along with
- a <filename>schema/</filename> directory contains SQL Server-specific
- scripts requires to set up the database. The JAR extension file will need to
- be placed within the <filename>GUACAMOLE_HOME/extensions</filename> folder,
- while the SQL Server JDBC driver must be placed within the
- <filename>GUACAMOLE_HOME/lib</filename> directory.</para>
- <para><emphasis>The SQL Server JDBC driver is not included with the extension.</emphasis> You
- must obtain the JDBC driver <filename>.jar</filename> yourself and place it in the directory.
- Furthermore, the SQL Server authentication extension supports a number of TDS-compatible
- drivers, so you must make sure the one you choose is supported by the extension, that the
- extension is configured properly, and that the <filename>.jar</filename> is in the correct
- directory. Microsoft's JDBC driver can be downloaded from Microsoft's <link
- xlink:href="https://docs.microsoft.com/en-us/sql/connect/sql-connection-libraries#anchor-20-drivers-relational-access">
- SQL Connection Libraries</link> page.</para>
- <para>In addition to the various parameters mentioned below, the SQL Server driver implements
- two parameters to control SQL Server-specific configuration items:
- <property>sqlserver-driver</property> and <property>sqlserver-instance</property>.</para>
- <para>The <property>sqlserver-instance</property> property controls the instance name that the
- SQL Server driver should attempt to connect to, if it is something other than the default
- SQL Server instance. This instance name is configured during the SQL Server installation.
- This property is optional, and most installations should work without the need to specify
- an instance name.</para>
- <para>The <property>sqlserver-driver</property> allows you to choose the compatibility mode of
- of the module with various TDS-compatible drivers such that it can be used with different
- versions of SQL Server and even non-Microsoft SQL Server TDS-compatible databases. The
- following options are available for the <property>sqlserver-driver</property> property:
- <variablelist>
- <varlistentry>
- <term>microsoft2005</term>
- <listitem>
- <para>The current Microsoft driver, supporting SQL Server 2005 and later.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>microsoft</term>
- <listitem>
- <para>The legacy SQL Server support.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>jtds</term>
- <listitem>
- <para>The open source JTDS driver.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>datadirect</term>
- <listitem>
- <para>The Progress Sybase driver.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Only one of the directories within the archive will be applicable to you, depending on
- whether you are using MariaDB, MySQL, PostgreSQL, or SQL Server.</para>
- </section>
- <section xml:id="jdbc-auth-database-creation">
- <title>Creating the Guacamole database</title>
- <para>The database authentication module will need a database to store authentication data
- and a user to use only for data access and manipulation. You can use an existing
- database and existing user, but for the sake of simplicity and security, these
- instructions assume you will be creating a new database and new user that will be used
- only by Guacamole and only for this authentication module.</para>
- <para>You need MariaDB, MySQL, PostgreSQL, or SQL Server installed, and must have sufficient
- access to create and administer databases. If this is not the case, install your database
- of choice now. Most distributions will provide a convenient MySQL or PostgreSQL package
- which will set up everything for you, including the root database user, if
- applicable. If you're using SQL Server, you need to install the packages on your platform
- of choice, and also make sure that you obtain the proper licensing for the version
- and edition of SQL Server you are running.</para>
- <para>For the sake of clarity, these instructions will refer to the database as
- "guacamole_db", but the database can be named whatever you like.</para>
- <section xml:id="jdbc-auth-mysql">
- <title>MySQL</title>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>ls schema/</userinput>
-<computeroutput>001-create-schema.sql 002-create-admin-user.sql upgrade</computeroutput>
-<prompt>$</prompt> <userinput>cat schema/*.sql | mysql -u root -p <replaceable>guacamole_db</replaceable></userinput>
-<prompt>Enter password:</prompt> <userinput><replaceable>password</replaceable></userinput>
-<prompt>$</prompt></screen>
- </informalexample>
- </section>
- <section xml:id="jdbc-auth-postgresql">
- <title>PostgreSQL</title>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>createdb <replaceable>guacamole_db</replaceable></userinput>
-<prompt>$</prompt> <userinput>ls schema/</userinput>
-<computeroutput>001-create-schema.sql 002-create-admin-user.sql</computeroutput>
-<prompt>$</prompt> <userinput>cat schema/*.sql | psql -d <replaceable>guacamole_db</replaceable> -f -</userinput>
-<computeroutput>CREATE TYPE
-CREATE TYPE
-CREATE TYPE
-CREATE TABLE
-CREATE INDEX</computeroutput>
-...
-<computeroutput>INSERT 0 1
-INSERT 0 4
-INSERT 0 3</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- </section>
- <section xml:id="jdbc-auth-sqlserver">
- <title>SQL Server</title>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -d <replaceable>guacamole_db</replaceable> -i schema/001-create-schema.sql</userinput>
-<prompt>Password:</prompt> <userinput><replaceable>password</replaceable></userinput>
-<computeroutput>Rule bound to data type.
-The new rule has been bound to column(s) of the specified user data type.
-Rule bound to data type.
-The new rule has been bound to column(s) of the specified user data type.</computeroutput>
-<prompt>$</prompt> <userinput>/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -d <replaceable>guacamole_db</replaceable> -i schema/002-create-admin-user.sql</userinput>
-<prompt>Password:</prompt> <userinput><replaceable>password</replaceable></userinput>
-<computeroutput>
-(1 rows affected)
-
-(3 rows affected)
-
-(5 rows affected)</computeroutput>
-</screen>
- </informalexample>
- </section>
- </section>
- <section>
- <title>Upgrading an existing Guacamole database</title>
- <para>If you are upgrading from an older version of Guacamole, you may need to run one or
- more database schema upgrade scripts located within the
- <filename>schema/upgrade/</filename> directory. Each of these scripts is named
- <filename>upgrade-pre-<replaceable>VERSION</replaceable>.sql</filename> where
- <replaceable>VERSION</replaceable> is the version of Guacamole where those changes
- were introduced. They need to be run when you are upgrading from a version of Guacamole
- older than <replaceable>VERSION</replaceable>.</para>
- <para>If there are no
- <filename>upgrade-pre-<replaceable>VERSION</replaceable>.sql</filename> scripts
- present in the <filename>schema/upgrade/</filename> directory which apply to your
- existing Guacamole database, then the schema has not changed between your version and
- the version your are installing, and there is no need to run any database upgrade
- scripts.</para>
- <para>These scripts are incremental and, when relevant, <emphasis>must be run in
- order</emphasis>. For example, if you are upgrading an existing database from
- version 0.9.13-incubating to version 1.0.0, you would need to run the
- <filename>upgrade-pre-0.9.14.sql</filename> script (because 0.9.13-incubating is
- older than 0.9.14), followed by the <filename>upgrade-pre-1.0.0.sql</filename> script
- (because 0.9.13-incubating is also older than 1.0.0).</para>
- <important xml:id="jdbc-auth-postgresql-upgrade">
- <para>Because the permissions granted to the Guacamole-specific PostgreSQL user when the
- database was first created will not automatically be granted for any new tables and
- sequences, you will also need to re-grant those permissions after applying any
- upgrade relevant scripts:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>psql -d <replaceable>guacamole_db</replaceable></userinput>
-<computeroutput>psql (9.3.6)
-Type "help" for help.
-</computeroutput>
-<prompt>guacamole=# </prompt><userinput>GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO <replaceable>guacamole_user</replaceable>;</userinput>
-<computeroutput>GRANT</computeroutput>
-<prompt>guacamole=# </prompt><userinput>GRANT SELECT,USAGE ON ALL SEQUENCES IN SCHEMA public TO <replaceable>guacamole_user</replaceable>;</userinput>
-<computeroutput>GRANT</computeroutput>
-<prompt>guacamole=# </prompt><userinput>\q</userinput>
-<prompt>$</prompt></screen>
- </informalexample>
- </important>
- </section>
- <section>
- <title>Granting Guacamole access to the database</title>
- <para>For Guacamole to be able to execute queries against the database, you must create a
- new user for the database and grant that user sufficient privileges to manage the
- contents of all tables in the database. The user created for Guacamole needs only
- <code>SELECT</code>, <code>UPDATE</code>, <code>INSERT</code>, and
- <code>DELETE</code> permissions on all Guacamole tables. Additionally, if using
- PostgreSQL, the user will need <code>SELECT</code> and <code>USAGE</code> permission on
- all sequences within all Guacamole tables. <emphasis>No other permissions should be
- granted.</emphasis></para>
- <para>These instructions will refer to the user as "guacamole_user" but the user can be
- named whatever you like. Naturally, you should also choose a real password for your user
- rather than the string "some_password" used as a placeholder below.</para>
- <section>
- <title>MySQL</title>
- <informalexample>
- <screen><prompt>$</prompt> mysql -u root -p
-<prompt>Enter password:</prompt> <userinput><replaceable>password</replaceable></userinput>
-<computeroutput>Welcome to the MySQL monitor. Commands end with ; or \g.
-Your MySQL connection id is 233
-Server version: 5.5.29-0ubuntu0.12.10.1 (Ubuntu)
-
-Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
-
-Oracle is a registered trademark of Oracle Corporation and/or its
-affiliates. Other names may be trademarks of their respective
-owners.
-
-Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
-</computeroutput>
-<prompt>mysql></prompt> <userinput>CREATE DATABASE <replaceable>guacamole_db</replaceable>;</userinput>
-<computeroutput>Query OK, 1 row affected (0.00 sec)</computeroutput>
-
-<prompt>mysql></prompt> <userinput>CREATE USER '<replaceable>guacamole_user'</replaceable>@'localhost' IDENTIFIED BY '<replaceable>some_password</replaceable>';</userinput>
-<computeroutput>Query OK, 0 rows affected (0.00 sec)</computeroutput>
-
-<prompt>mysql></prompt> <userinput>GRANT SELECT,INSERT,UPDATE,DELETE ON <replaceable>guacamole_db</replaceable>.* TO '<replaceable>guacamole_user'</replaceable>@'localhost';</userinput>
-<computeroutput>Query OK, 0 rows affected (0.00 sec)</computeroutput>
-
-<prompt>mysql></prompt> <userinput>FLUSH PRIVILEGES;</userinput>
-<computeroutput>Query OK, 0 rows affected (0.02 sec)</computeroutput>
-
-<prompt>mysql></prompt> <userinput>quit</userinput>
-<computeroutput>Bye</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- </section>
- <section>
- <title>PostgreSQL</title>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>psql -d <replaceable>guacamole_db</replaceable></userinput>
-<computeroutput>psql (9.3.6)
-Type "help" for help.
-</computeroutput>
-<prompt>guacamole=# </prompt><userinput>CREATE USER <replaceable>guacamole_user</replaceable> WITH PASSWORD '<replaceable>some_password</replaceable>';</userinput>
-<computeroutput>CREATE ROLE</computeroutput>
-<prompt>guacamole=# </prompt><userinput>GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO <replaceable>guacamole_user</replaceable>;</userinput>
-<computeroutput>GRANT</computeroutput>
-<prompt>guacamole=# </prompt><userinput>GRANT SELECT,USAGE ON ALL SEQUENCES IN SCHEMA public TO <replaceable>guacamole_user</replaceable>;</userinput>
-<computeroutput>GRANT</computeroutput>
-<prompt>guacamole=# </prompt><userinput>\q</userinput>
-<prompt>$</prompt></screen>
- </informalexample>
- </section>
- <section>
- <title>SQL Server</title>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>/opt/mssql-tools/bin/sqlcmd -S localhost -U SA</userinput>
-<prompt>Password:</prompt> <userinput><replaceable>password</replaceable></userinput>
-<prompt>1></prompt> <userinput>CREATE DATABASE <replaceable>guacamole_db</replaceable>;</userinput>
-<prompt>2></prompt> <userinput>GO</userinput>
-<prompt>1></prompt> <userinput>CREATE LOGIN <replaceable>guacamole_user</replaceable> WITH PASSWORD = '<replaceable>some_password</replaceable>';</userinput>
-<prompt>2></prompt> <userinput>GO</userinput>
-<prompt>1></prompt> <userinput>USE <replaceable>guacamole_db</replaceable>;</userinput>
-<prompt>2></prompt> <userinput>GO</userinput>
-<prompt>1></prompt> <userinput>CREATE USER <replaceable>guacamole_user</replaceable>;</userinput>
-<prompt>2></prompt> <userinput>GO</userinput>
-<prompt>1></prompt> <userinput>ALTER ROLE db_datawriter ADD MEMBER <replaceable>guacamole_user</replaceable>;</userinput>
-<prompt>2></prompt> <userinput>ALTER ROLE db_datareader ADD MEMBER <replaceable>guacamole_user</replaceable>;</userinput>
-<prompt>3></prompt> <userinput>GO</userinput></screen>
- </informalexample>
- </section>
- </section>
- <section xml:id="jdbc-auth-installation">
- <title>Installing database authentication</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- located within the <filename>GUACAMOLE_HOME/extensions</filename> directory. To install
- the database authentication extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Copy <filename>guacamole-auth-jdbc-mysql-1.3.0.jar</filename>
- <emphasis>or</emphasis>
- <filename>guacamole-auth-jdbc-postgresql-1.3.0.jar</filename>
- <emphasis>or</emphasis>
- <filename>guacamole-auth-jdbc-sqlserver-1.3.0.jar</filename> within
- <filename>GUACAMOLE_HOME/extensions</filename>, depending on whether you are
- using MySQL/MariaDB, PostgreSQL, or SQL Server.</para>
- </step>
- <step>
- <para>Copy the JDBC driver for your database to
- <filename>GUACAMOLE_HOME/lib</filename>. Without a JDBC driver for your
- database, Guacamole will not be able to connect and authenticate users.</para>
- </step>
- <step>
- <para>Configure Guacamole to use database authentication, as described below.</para>
- </step>
- </procedure>
- <important>
- <para>You will need to restart Guacamole by restarting your servlet container in order
- to complete the installation. Doing this will disconnect all active users, so be
- sure that it is safe to do so prior to attempting installation. If you do not
- configure the database authentication properly, Guacamole will not start up again
- until the configuration is fixed.</para>
- </important>
- <section xml:id="jdbc-auth-configuration">
- <title>Configuring Guacamole for database authentication</title>
- <para>Additional properties must be added to <filename>guacamole.properties</filename>
- for Guacamole to properly connect to your database. These properties are specific to
- the database being used, and must be set correctly for authentication to
- work.</para>
- <para>To use a MySQL database, you will need to specify the following:</para>
- <informalexample>
- <programlisting># MySQL properties
-mysql-hostname: localhost
-mysql-port: 3306
-mysql-database: <replaceable>guacamole_db</replaceable>
-mysql-username: <replaceable>guacamole_user</replaceable>
-mysql-password: <replaceable>some_password</replaceable>
- </programlisting>
- </informalexample>
- <para>For PostgreSQL, the properties are similar, but with different prefixes:</para>
- <informalexample>
- <programlisting># PostgreSQL properties
-postgresql-hostname: localhost
-postgresql-port: 5432
-postgresql-database: <replaceable>guacamole_db</replaceable>
-postgresql-username: <replaceable>guacamole_user</replaceable>
-postgresql-password: <replaceable>some_password</replaceable>
- </programlisting>
- </informalexample>
- <para>The SQL Server properties follow the same format:</para>
- <informalexample>
- <programlisting># SQL Server properties
-sqlserver-hostname: localhost
-sqlserver-port: 1433
-sqlserver-database: <replaceable>guacamole_db</replaceable>
-sqlserver-username: <replaceable>guacamole_user</replaceable>
-sqlserver-password: <replaceable>some_password</replaceable>
-sqlserver-driver: microsoft2005
- </programlisting>
- </informalexample>
- <para>The properties absolutely required by the database authentication extension are
- relatively few and self-explanatory, describing only how the connection to the
- database is to be established, and how Guacamole will authenticate when querying the
- database:</para>
- <informaltable frame="all">
- <tgroup cols="4">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="1*"/>
- <colspec colname="c3" colnum="3" colwidth="1*"/>
- <colspec colname="c4" colnum="4" colwidth="2*"/>
- <thead>
- <row>
- <entry>MySQL/MariaDB Property</entry>
- <entry>PostgreSQL Property</entry>
- <entry>SQL Server Property</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><property>mysql-hostname</property></entry>
- <entry><property>postgresql-hostname</property></entry>
- <entry><property>sqlserver-hostname</property></entry>
- <entry>
- <para>The hostname or IP address of the server hosting your
- database.</para>
- </entry>
- </row>
- <row>
- <entry><property>mysql-port</property></entry>
- <entry><property>postgresql-port</property></entry>
- <entry><property>sqlserver-port</property></entry>
- <entry>
- <para>The port number of the database to connect to. For MySQL and
- MariaDB, this will likely be 3306. For PostgreSQL, this will
- likely be 5432.</para>
- </entry>
- </row>
- <row>
- <entry><property>mysql-database</property></entry>
- <entry><property>postgresql-database</property></entry>
- <entry><property>sqlserver-database</property></entry>
- <entry>
- <para>The name of the database that you created for Guacamole. This
- is given as "guacamole_db" in the examples given in this
- chapter.</para>
- </entry>
- </row>
- <row>
- <entry><property>mysql-username</property></entry>
- <entry><property>postgresql-username</property></entry>
- <entry><property>sqlserver-username</property></entry>
- <entry>
- <para>The username of the user that Guacamole should use to connect
- to the database. This is given as "guacamole_user" in the
- examples given in this chapter.</para>
- </entry>
- </row>
- <row>
- <entry><property>mysql-password</property></entry>
- <entry><property>postgresql-password</property></entry>
- <entry><property>sqlserver-password</property></entry>
- <entry>
- <para>The password Guacamole should provide when authenticating with
- the database. This is given as "some_password" in the examples
- given in this chapter.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>Be sure to specify the correct username and password for the database user you
- created, and to specify the correct database. Authentication will not work if these
- parameters are not correct.</para>
- <section>
- <title>Enforcing password policies</title>
- <para>Configuration options are available for enforcing rules intended to encourage
- password complexity and regular changing of passwords. None of these options are
- enabled by default, but can be selectively enabled through additional properties
- in <filename>guacamole.properties</filename>.</para>
- <section>
- <title>Password complexity</title>
- <para>Administrators can require that passwords have a certain level of
- complexity, such as having both uppercase and lowercase letters ("multiple
- case"), at least one digit, or at least one symbol, and can prohibit
- passwords from containing the user's own username.</para>
- <para>With respect to password content, the database authentication defines a
- "digit" as any numeric character and a "symbol" is any non-alphanumeric
- character. This takes non-English languages into account, thus a digit is
- not simply "0" through "9" but rather <link
- xlink:href="https://en.wikipedia.org/wiki/Numerals_in_Unicode">any
- character defined in Unicode as numeric</link>, and a symbol is any
- character which Unicode does not define as alphabetic or numeric.</para>
- <para>The check for whether a password contains the user's own username is
- performed in a case-insensitive manner. For example, if the user's username
- is "phil", the passwords "ch!0roPhil" and "PHIL-o-dendr0n" would still be
- prohibited.</para>
- <informalexample>
- <programlisting># MySQL
-mysql-user-password-min-length: <replaceable>8</replaceable>
-mysql-user-password-require-multiple-case: true
-mysql-user-password-require-symbol: true
-mysql-user-password-require-digit: true
-mysql-user-password-prohibit-username: true
-
-# PostgreSQL
-postgresql-user-password-min-length: <replaceable>8</replaceable>
-postgresql-user-password-require-multiple-case: true
-postgresql-user-password-require-symbol: true
-postgresql-user-password-require-digit: true
-postgresql-user-password-prohibit-username: true
-
-# SQL Server
-sqlserver-user-password-min-length: <replaceable>8</replaceable>
-sqlserver-user-password-require-multiple-case: true
-sqlserver-user-password-require-symbol: true
-sqlserver-user-password-require-digit: true
-sqlserver-user-password-prohibit-username: true</programlisting>
- </informalexample>
- </section>
- <section>
- <title>Password age / expiration</title>
- <para>"Password age" refers to two separate concepts:</para>
- <orderedlist>
- <listitem>
- <para>Requiring users to change their password after a certain amount of
- time has elapsed since the last password change (maximum password
- age).</para>
- </listitem>
- <listitem>
- <para>Preventing users from changing their password too frequently
- (minimum password age).</para>
- </listitem>
- </orderedlist>
- <para>While it may seem strange to prevent users from changing their password
- too frequently, it does make sense if you are concerned that rapid password
- changes may defeat password expiration (users could immediately change the
- password back) or tracking of password history (users could cycle through
- passwords until the history is exhausted and their old password is usable
- again).</para>
- <para>By default, the database authentication does not apply any limits to
- password age, and users with permission to change their passwords may do so
- as frequently or infrequently as they wish. Password age limits can be
- enabled using a pair of properties, each accepting values given in units of
- days:</para>
- <informalexample>
- <programlisting># MySQL
-mysql-user-password-min-age: <replaceable>7</replaceable>
-mysql-user-password-max-age: <replaceable>90</replaceable>
-
-# PostgreSQL
-postgresql-user-password-min-age: <replaceable>7</replaceable>
-postgresql-user-password-max-age: <replaceable>90</replaceable>
-
-# SQL Server
-sqlserver-user-password-min-age: <replaceable>7</replaceable>
-sqlserver-user-password-max-age: <replaceable>90</replaceable></programlisting>
- </informalexample>
- <important>
- <para>So that administrators can always intervene in the case that a
- password needs to be reset despite restrictions, the minimum age
- restriction does not apply to any user with permission to administer the
- system.</para>
- </important>
- </section>
- <section>
- <title>Preventing password reuse</title>
- <para>If desired, Guacamole can keep track of each user's most recently used
- passwords, and will prohibit reuse of those passwords until the password has
- been changed sufficiently many times. By default, Guacamole will not keep
- track of old passwords.</para>
- <para>Note that these passwords are hashed in the same manner as each user's
- current password. When a user's password is changed, the hash, salt, etc.
- currently stored for that user is actually just copied verbatim (along with
- a timestamp) into a list of historical passwords, with older entries from
- this list being automatically deleted.</para>
- <informalexample>
- <programlisting># MySQL
-mysql-user-password-history-size: <replaceable>6</replaceable>
-
-# PostgreSQL
-postgresql-user-password-history-size: <replaceable>6</replaceable>
-
-# SQL Server
-sqlserver-user-password-history-size: <replaceable>6</replaceable></programlisting>
- </informalexample>
- </section>
- </section>
- <section xml:id="jdbc-auth-concurrency">
- <title>Concurrent use of Guacamole connections</title>
- <para>The database authentication module provides configuration options to restrict
- concurrent use of connections or connection groups. These options are set
- through <filename>guacamole.properties</filename> and specify the default
- concurrency policies for connections and connection groups. The values set
- through the properties can be overridden later on a per-connection basis using
- the administrative interface:</para>
- <informalexample>
- <programlisting># MySQL
-mysql-default-max-connections: 1
-mysql-default-max-group-connections: 1
-
-# PostgreSQL
-postgresql-default-max-connections: 1
-postgresql-default-max-group-connections: 1
-
-# SQL Server
-sqlserver-default-max-connections: 1
-sqlserver-default-max-group-connections: 1</programlisting>
- </informalexample>
- <para>These properties are not required, but with the above properties in place,
- users attempting to use a connection or group that is already in use will be
- denied access. By default, concurrent access is allowed.</para>
- <para>Concurrent access can also be restricted such that a particular user may only
- use a connection or group a certain number of times. By default, per-user
- concurrent use is limited for connection groups (to avoid allowing a single user
- to exhaust the contents of the group) but otherwise unrestricted. This default
- behavior can be modified through <filename>guacamole.properties</filename> or
- the per-connection settings exposed in the administrative interface:</para>
- <informalexample>
- <programlisting># MySQL
-mysql-default-max-connections-per-user: 0
-mysql-default-max-group-connections-per-user: 0
-
-# PostgreSQL
-postgresql-default-max-connections-per-user: 0
-postgresql-default-max-group-connections-per-user: 0
-
-# SQL Server
-sqlserver-default-max-connections-per-user: 0
-sqlserver-default-max-group-connections-per-user: 0</programlisting>
- </informalexample>
- <para>If you wish to impose an absolute limit on the number of connections that can
- be established through Guacamole, ignoring which users or connections are
- involved, this can be done as well. By default, Guacamole will impose no such
- limit:</para>
- <informalexample>
- <programlisting># MySQL
-mysql-absolute-max-connections: 0
-
-# PostgreSQL
-postgresql-absolute-max-connections: 0
-
-# SQL Server
-sqlserver-absolute-max-connections: 0</programlisting>
- </informalexample>
- </section>
- </section>
- <section xml:id="jdbc-auth-restrict">
- <title>Restricting authentication to database users only</title>
- <para>By default, users will be allowed access to Guacamole as long as they are
- authenticated by at least one extension. If database authentication is in use, and a
- user is not associated with the database, then that user will be allowed access to
- Guacamole if another extension grants this access, and will be provided with a view
- of the data exposed by other extensions for that user account.</para>
- <para>In some situations, such as when <link linkend="ldap-and-database">combining LDAP
- with a database</link>, it would be preferable to let the database have the last
- word regarding whether a user should be allowed into the system: restricting access
- to only those users which exist in the database, and explicitly denying
- authentication through all other means unless that user has been associated with the
- database as well. This behavior can be forced by setting properties which declare
- that database user accounts are required:</para>
- <informalexample>
- <programlisting># MySQL
-mysql-user-required: true
-
-# PostgreSQL
-postgresql-user-required: true
-
-# SQL Server
-sqlserver-user-required: true</programlisting>
- </informalexample>
- <para>With the above properties set, successful authentication attempts for users which
- are not associated with the database will be vetoed by the database authentication.
- Guacamole will report that the login is invalid, as if the user does not exist at
- all.</para>
- </section>
- <section xml:id="jdbc-auth-auto-create">
- <title>Auto-creating database users</title>
- <para>Guacamole supports the ability to layer authentication modules on top of one another
- such that users successfully authenticated from one extension (e.g. LDAP) can be assigned
- permissions to connections in another extension (e.g. JDBC). Other extensions, like the
- TOTP extension, rely on the database extension to be able to store information for
- various user accounts. In these situations it can be difficult to have to manually
- create user accounts within the database extension.</para>
- <para>The database extension provides a mechanism for enabling auto-creation of user
- accounts that successfully authenticate from other extensions. This functionality
- is disabled by default, but can be enabled in each of the supported database
- extensions by enabling the appropriate option in guacamole.properties. The
- resulting accounts will only have READ access to themselves until additional
- permissions are granted, either explicitly by the administrator or by
- permissions assigned to groups of which the user is a member.</para>
- <informalexample>
- <programlisting># MySQL
-mysql-auto-create-accounts: true
-
-# PostgreSQL
-postgresql-auto-create-accounts: true
-
-# SQL Server
-sqlserver-auto-create-accounts: true</programlisting>
- </informalexample>
- </section>
- <section>
- <title>Completing the installation</title>
- <para>Guacamole will only reread <filename>guacamole.properties</filename> and load
- newly-installed extensions during startup, so your servlet container will need to be
- restarted before the database authentication will take effect. Restart your servlet
- container and give the new authentication a try.</para>
- <para>
- <important>
- <para>You only need to restart your servlet container. <emphasis>You do not need
- to restart <package>guacd</package></emphasis>.</para>
- <para><package>guacd</package> is completely independent of the web application
- and does not deal with <filename>guacamole.properties</filename> or the
- authentication system in any way. Since you are already restarting the
- servlet container, restarting <package>guacd</package> as well technically
- won't hurt anything, but doing so is completely pointless.</para>
- </important>
- </para>
- <para>If Guacamole does not come back online after restarting your servlet container,
- check the logs. Problems in the configuration of the database authentication
- extension will prevent Guacamole from starting up, and any such errors will be
- recorded in the logs of your servlet container.</para>
- </section>
- </section>
- <section xml:id="jdbc-auth-default-user">
- <title>Logging in</title>
- <indexterm>
- <primary>default user</primary>
- </indexterm>
- <indexterm>
- <primary><systemitem>guacadmin</systemitem></primary>
- </indexterm>
- <para>The default Guacamole user created by the provided SQL scripts is
- "<systemitem>guacadmin</systemitem>", with a default password of
- "<systemitem>guacadmin</systemitem>". Once you have verified that the database
- authentication is working, <emphasis>you should change your password
- immediately</emphasis>.</para>
- <para>More detailed instructions for managing users and connections is given in <xref
- linkend="administration"/>.</para>
- </section>
- <section xml:id="jdbc-auth-schema">
- <title>Modifying data manually</title>
- <indexterm>
- <primary>schema</primary>
- </indexterm>
- <para>If necessary, it is possible to modify the data backing the authentication module
- manually by executing SQL statements against the database. In general use, this will not
- be common, but if you need to bulk-insert a large number of users or connections, or you
- wish to translate an existing configuration automatically, you will need to know how
- everything is laid out at a high level.</para>
- <para>This section assumes knowledge of SQL and your chosen database, and that whatever you
- need to do can be accomplished if only you had high-level information about Guacamole's
- SQL schema.</para>
- <section xml:id="jdbc-auth-schema-entities">
- <title>Entities</title>
- <indexterm>
- <primary><classname>guacamole_entity</classname></primary>
- </indexterm>
- <para>Every user and user group has a corresponding entry in the
- <classname>guacamole_entity</classname> table which serves as the basis for
- assignment of a unique name, permissions, as well as relations which are common to
- both users and groups like group membership. Each entity has a corresponding name
- which is unique across all other entities of the same type.</para>
- <para>If deleting a user or user group, the corresponding entity should also be deleted.
- As any user or group which points to the entity will be deleted automatically when
- the entity is deleted through cascading deletion, <emphasis>it is advisable to use
- the entity as the basis for any delete operation</emphasis>.</para>
- <para>The <classname>guacamole_entity</classname> table contains the following
- columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>entity_id</property></term>
- <listitem>
- <para>The unique integer associated with each entity (user or user group).
- This value is generated automatically when a new entry is inserted into
- the <classname>guacamole_entity</classname> table and is distinct from
- the unique integer associated with the user entry in <link
- linkend="jdbc-auth-schema-users"
- ><classname>guacamole_user</classname></link> or the user group
- entry in <link linkend="jdbc-auth-schema-groups"
- ><classname>guacamole_user_group</classname></link>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>name</property></term>
- <listitem>
- <para>The unique name associated with each user or group. This value must be
- specified manually, and must be different from any existing user or
- group in the table. The name need only be unique relative to the names
- of other entities having the same type (a user may have the same name as
- a group).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>type</property></term>
- <listitem>
- <para>The type of this entity. This can be either <type>USER</type> or
- <type>USER_GROUP</type>.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="jdbc-auth-schema-users">
- <title>Users</title>
- <indexterm>
- <primary><classname>guacamole_user</classname></primary>
- </indexterm>
- <para>Every user has a corresponding entry in the <classname>guacamole_user</classname>
- and <link linkend="jdbc-auth-schema-entities"
- ><classname>guacamole_entity</classname></link> tables. Each user has a
- corresponding unique username, specified via
- <classname>guacamole_entity</classname>, and salted password. The salted password is
- split into two columns: one containing the salt, and the other containing the
- password hashed with SHA-256.</para>
- <para>If deleting a user, the <link linkend="jdbc-auth-schema-entities">corresponding
- entity</link> should also be deleted. As any user which points to the entity
- will be deleted automatically when the entity is deleted through cascading deletion,
- <emphasis>it is advisable to use the entity as the basis for any delete
- operation</emphasis>.</para>
- <para>The <classname>guacamole_user</classname> table contains the following
- columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>user_id</property></term>
- <listitem>
- <para>The unique integer associated with each user. This value is generated
- automatically when a new entry is inserted into the
- <classname>guacamole_user</classname> table.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>entity_id</property></term>
- <listitem>
- <para>The value of the <property>entity_id</property> column of the
- <classname>guacamole_entity</classname> entry representing this
- user.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>password_hash</property></term>
- <listitem>
- <para>The result of hashing the user's password concatenated with the
- contents of <property>password_salt</property> using SHA-256. The salt
- is appended to the password prior to hashing.</para>
- <para>Although passwords set through Guacamole will always be salted, it is
- possible to use unsalted password hashes when inserted manually or
- through an external system. If <property>password_salt</property> is
- <constant>NULL</constant>, the <property>password_hash</property>
- will be handled as a simple unsalted hash of the password.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>password_salt</property></term>
- <listitem>
- <para>A 32-byte random value. When a new user is created from the web
- interface, this value is randomly generated using a
- cryptographically-secure random number generator.</para>
- <para>This will always be set for users whose passwords are set through
- Guacamole, but it is possible to use unsalted password hashes when
- inserted manually or through an external system. If
- <property>password_salt</property> is <constant>NULL</constant>, the
- <property>password_hash</property> will be handled as a simple
- unsalted hash of the password.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>password_date</property></term>
- <listitem>
- <para>The date (and time) that the password was last changed. When a
- password is changed via the Guacamole interface, this value is updated.
- This, along with the contents of the
- <classname>guacamole_user_password_history</classname> table, is
- used to enforce password policies.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>disabled</property></term>
- <listitem>
- <para>Whether login attempts as this user account should be rejected. If
- this column is set to <constant>TRUE</constant> or
- <constant>1</constant>, login attempts by this user will be rejected
- as if the user did not exist. By default, user accounts are not
- disabled, and login attempts will succeed if the user provides the
- correct password.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>expired</property></term>
- <listitem>
- <para>If set to <constant>TRUE</constant> or <constant>1</constant>,
- requires that the user reset their password prior to fully logging in.
- The user will be presented with a password reset form, and will not be
- allowed to log into Guacamole until the password has been changed. By
- default, user accounts are not expired, and no password reset will be
- required upon login.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>access_window_start</property></term>
- <listitem>
- <para>The time of day (not date) after which this user account may be used.
- If <constant>NULL</constant>, this restriction does not apply. If set to
- non-<constant>NULL</constant>, attempts to log in after the
- specified time will be allowed, while attempts to log in before the
- specified time will be denied.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>access_window_end</property></term>
- <listitem>
- <para>The time of day (not date) after which this user account may
- <emphasis>not</emphasis> be used. If <constant>NULL</constant>, this
- restriction does not apply. If set to non-<constant>NULL</constant>,
- attempts to log in after the specified time will be denied, while
- attempts to log in before the specified time will be allowed.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>valid_from</property></term>
- <listitem>
- <para>The date (not time of day) after which this user account may be used.
- If <constant>NULL</constant>, this restriction does not apply. If set to
- non-<constant>NULL</constant>, attempts to log in after the
- specified date will be allowed, while attempts to log in before the
- specified date will be denied.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>valid_until</property></term>
- <listitem>
- <para>The date (not time of day) after which this user account may
- <emphasis>not</emphasis> be used. If <constant>NULL</constant>, this
- restriction does not apply. If set to non-<constant>NULL</constant>,
- attempts to log in after the specified date will be denied, while
- attempts to log in before the specified date will be allowed.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>timezone</property></term>
- <listitem>
- <para>The time zone to use when interpreting the
- <property>access_window_start</property>,
- <property>access_window_end</property>,
- <property>valid_from</property>, and
- <property>valid_until</property> values. This value may be any Java
- <classname>TimeZone</classname> ID, as defined by <link
- xlink:href="http://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html#getAvailableIDs()"
- ><methodname>getAvailableIDs()</methodname></link>, though the
- Guacamole management interface will only present a subset of these time
- zones.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>full_name</property></term>
- <listitem>
- <para>The user's full name. Unlike the username, this name need not be
- unique; it is optional and is meant for display purposes only. Defining
- this value has no bearing on user identity, which is dictated purely by
- the username. User accounts with no associated full name should have
- this column set to <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>email_address</property></term>
- <listitem>
- <para>The user's email address, if any. This value is optional, need not be
- unique relative to other defined users, and is meant for display
- purposes only. Defining this value has no bearing on user identity,
- which is dictated purely by the username. If the user has no associated
- email address, this column should be set to
- <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>organization</property></term>
- <listitem>
- <para>The name of the organization, company, etc. that the user is
- affiliated with. This value is optional and is meant for display
- purposes only. Defining this value has no bearing on user identity,
- which is dictated purely by the username. Users with no associated
- organization should have this column set to
- <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>organizational_role</property></term>
- <listitem>
- <para>The role or title of the user at the organization described by the
- <property>organization</property> column. This value is optional and
- is used for display purposes only. Defining this value has no bearing on
- user identity, which is dictated purely by the username. Users with no
- associated organization (or specific role/title at that organization)
- should have this column set to <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <important>
- <para>If you choose to manually set unsalted password hashes, please be sure you
- understand the security implications of doing so.</para>
- <para>In the event that your database is compromised, finding the password for a
- <emphasis>salted</emphasis> hash is computationally infeasible, but finding
- the password for an <emphasis>unsalted</emphasis> hash is often not. In many
- cases, the password which corresponds to an unsalted hash can be found simply by
- entering the hash into a search engine like Google.</para>
- </important>
- <para>If creating a user manually, the main complication is the salt, which must be
- determined before the <command>INSERT</command> statement can be constructed, but
- this can be dealt with using variables. For MySQL:</para>
- <informalexample>
- <programlisting>-- Generate salt
-SET @salt = UNHEX(SHA2(UUID(), 256));
-
--- Create base entity entry for user
-INSERT INTO guacamole_entity (name, type)
-VALUES ('<replaceable>myuser</replaceable>', 'USER');
-
--- Create user and hash password with salt
-INSERT INTO guacamole_user (
- entity_id,
- password_salt,
- password_hash,
- password_date
-)
-SELECT
- entity_id,
- @salt,
- UNHEX(SHA2(CONCAT('<replaceable>mypassword</replaceable>', HEX(@salt)), 256)),
- CURRENT_TIMESTAMP
-FROM guacamole_entity
-WHERE
- name = '<replaceable>myuser</replaceable>'
- AND type = 'USER';</programlisting>
- </informalexample>
- <para>This sort of statement is useful for both creating new users or for changing
- passwords, especially if all administrators have forgotten theirs.</para>
- <para>If you are not using MySQL, or you are using a version of MySQL that lacks the
- <methodname>SHA2</methodname> function, you will need to calculate the SHA-256
- value manually (by using the <command>sha256sum</command> command, for
- example).</para>
- <section xml:id="jdbc-auth-schema-password-history">
- <title>Password history</title>
- <indexterm>
- <primary><classname>guacamole_user_password_history</classname></primary>
- </indexterm>
- <para>When a user's password is changed, a copy of the previous password's hash and
- salt is made within the <classname>guacamole_user_password_history</classname>.
- Each entry in this table is associated with the user whose password changed,
- along with the date that password first applied.</para>
- <para>Old entries within this table are automatically deleted on a per-user basis
- depending on the requirements of the password policy. For example, if the
- password policy has been configured to require that users not reuse any of their
- previous six passwords, then there will be no more than six entries in this
- table for each user.</para>
- <variablelist>
- <varlistentry>
- <term><property>password_history_id</property></term>
- <listitem>
- <para>The unique integer associated with each password history record.
- This value is generated automatically when a new entry is inserted
- into the <classname>guacamole_user_password_history</classname>
- table.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>user_id</property></term>
- <listitem>
- <para>The value of the <property>user_id</property> column from the
- entry in <classname>guacamole_user</classname> associated with the
- user who previously had this password.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>password_hash</property></term>
- <listitem>
- <para>The hashed password specified within the
- <property>password_hash</property> column of
- <classname>guacamole_user</classname> prior to the password
- being changed.</para>
- <para>In most cases, this will be a salted hash, though it is possible
- to force the use of unsalted hashes when making changes to the
- database manually or through an external system.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>password_salt</property></term>
- <listitem>
- <para>The salt value specified within the
- <property>password_salt</property> column of
- <classname>guacamole_user</classname> prior to the password
- being changed.</para>
- <para>This will always be set for users whose passwords are set through
- Guacamole, but it is possible to use unsalted password hashes when
- inserted manually or through an external system, in which case this
- may be <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>password_date</property></term>
- <listitem>
- <para>The date (and time) that the password was set. The time that the
- password ceased being used is recorded either by the password_date
- of the next related entry in
- <classname>guacamole_user_password_history</classname> or
- <property>password_date</property> of
- <classname>guacamole_user</classname> (if there is no such
- history entry).</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="jdbc-auth-schema-login-history">
- <title>Login history</title>
- <indexterm>
- <primary><classname>guacamole_user_history</classname></primary>
- </indexterm>
- <para>When a user logs in or out, a corresponding entry in the
- <classname>guacamole_user_history</classname> table is created or updated
- respectively. Each entry is associated with the user that logged in and the time
- their session began. If the user has logged out, the time their session ended is
- also stored.</para>
- <para>It is very unlikely that a user will need to update this table, but knowing
- the structure is potentially useful if you wish to generate a report of
- Guacamole usage. The <classname>guacamole_user_history</classname> table has the
- following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>history_id</property></term>
- <listitem>
- <para>The unique integer associated with each history record. This value
- is generated automatically when a new entry is inserted into the
- <classname>guacamole_user_history</classname> table.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>user_id</property></term>
- <listitem>
- <para>The value of the <property>user_id</property> from the entry in
- <classname>guacamole_user</classname> associated with the user
- that logged in. If the user no longer exists, this will be
- <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>username</property></term>
- <listitem>
- <para>The username associated with the user at the time that they logged
- in. This username value is not guaranteed to uniquely identify a
- user, as the original user may be subsequently renamed or
- deleted.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>remote_host</property></term>
- <listitem>
- <para>The hostname or IP address of the machine that the user logged in
- from, if known. If unknown, this will be
- <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>start_date</property></term>
- <listitem>
- <para>The time at which the user logged in. Despite its name, this
- column also stores time information in addition to the date.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>end_date</property></term>
- <listitem>
- <para>The time at which the user logged out. If the user is still
- active, the value in this column will be <constant>NULL</constant>.
- Despite its name, this column also stores time information in
- addition to the date.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </section>
- <section xml:id="jdbc-auth-schema-groups">
- <title>User groups</title>
- <indexterm>
- <primary><classname>guacamole_user_group</classname></primary>
- </indexterm>
- <para>Similar to <link linkend="jdbc-auth-schema-users">users</link>, every user group
- has a corresponding entry in the <classname>guacamole_user_group</classname> and
- <link linkend="jdbc-auth-schema-entities"
- ><classname>guacamole_entity</classname></link> tables. Each user group has
- a corresponding unique name specified via
- <classname>guacamole_entity</classname>.</para>
- <para>If deleting a user group, the <link linkend="jdbc-auth-schema-entities"
- >corresponding entity</link> should also be deleted. As any user group which
- points to the entity will be deleted automatically when the entity is deleted
- through cascading deletion, <emphasis>it is advisable to use the entity as the basis
- for any delete operation</emphasis>.</para>
- <para>The <classname>guacamole_user_group</classname> table contains the following
- columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>user_group_id</property></term>
- <listitem>
- <para>The unique integer associated with each user group. This value is
- generated automatically when a new entry is inserted into the
- <classname>guacamole_user_group</classname> table.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>entity_id</property></term>
- <listitem>
- <para>The value of the <property>entity_id</property> column of the
- <classname>guacamole_entity</classname> entry representing this user
- group.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>disabled</property></term>
- <listitem>
- <para>Whether membership within this group should be taken into account when
- determining the permissions granted to a particular user. If this column
- is set to <constant>TRUE</constant> or <constant>1</constant>,
- membership in this group will have no effect on user permissions,
- whether those permissions are granted to this group directly or
- indirectly through the groups that this group is a member of. By
- default, user groups are not disabled, and permissions granted to a user
- through the group will be taken into account.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <indexterm>
- <primary><classname>guacamole_user_group_member</classname></primary>
- </indexterm>
- <para>Membership within a user group is dictated through entries in the
- <classname>guacamole_user_group_member</classname> table. As both users and user
- groups may be members of groups, each entry associates the containing group with the
- entity of the member.</para>
- <para>The <classname>guacamole_user_group_member</classname> table contains the
- following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>user_group_id</property></term>
- <listitem>
- <para>The <property>user_group_id</property> value of the user group having
- the specified member.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>member_entity_id</property></term>
- <listitem>
- <para>The <property>entity_id</property> value of the user or user group
- that is a member of the specified group.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="jdbc-auth-schema-connections">
- <title>Connections and parameters</title>
- <indexterm>
- <primary><classname>guacamole_connection</classname></primary>
- </indexterm>
- <indexterm>
- <primary><classname>guacamole_connection_parameter</classname></primary>
- </indexterm>
- <para>Each connection has an entry in the <classname>guacamole_connection</classname>
- table, with a one-to-many relationship to parameters, stored as name/value pairs in
- the <classname>guacamole_connection_parameter</classname> table.</para>
- <para>The <classname>guacamole_connection</classname> table is simply a pairing of a
- unique and descriptive name with the protocol to be used for the connection. It
- contains the following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>connection_id</property></term>
- <listitem>
- <para>The unique integer associated with each connection. This value is
- generated automatically when a new entry is inserted into the
- <classname>guacamole_connection</classname> table.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>connection_name</property></term>
- <listitem>
- <para>The unique name associated with each connection. This value must be
- specified manually, and must be different from any existing connection
- name in the same connection group. References to connections in other
- tables use the value from <property>connection_id</property>, not
- <property>connection_name</property>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>protocol</property></term>
- <listitem>
- <para>The protocol to use with this connection. This is the name of the
- protocol that should be sent to <package>guacd</package> when
- connecting, for example "<constant>vnc</constant>" or
- "<constant>rdp</constant>".</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>parent_id</property></term>
- <listitem>
- <para>The unique integer associated with the connection group containing
- this connection, or <constant>NULL</constant> if this connection is
- within the root group.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>max_connections</property></term>
- <listitem>
- <para>The maximum number of concurrent connections to allow to this
- connection at any one time <emphasis>regardless of user</emphasis>.
- <constant>NULL</constant> will use the default value specified in
- <filename>guacamole.properties</filename> with the
- <property>mysql-default-max-connections</property> or
- <property>postgresql-default-max-connections</property> properties,
- and a value of <constant>0</constant> denotes unlimited.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>max_connections_per_user</property></term>
- <listitem>
- <para>The maximum number of concurrent connections to allow to this
- connection at any one time <emphasis>from a single user</emphasis>.
- <constant>NULL</constant> will use the default value specified in
- <filename>guacamole.properties</filename> with the
- <property>mysql-default-max-connections</property> or
- <property>postgresql-default-max-connections</property> properties,
- and a value of <constant>0</constant> denotes unlimited.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>proxy_hostname</property></term>
- <listitem>
- <para>The hostname or IP address of the Guacamole proxy daemon
- (<package>guacd</package>) which should be used for this connection.
- If <constant>NULL</constant>, the value defined with the
- <property>guacd-hostname</property> property in
- <filename>guacamole.properties</filename> will be used.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>proxy_port</property></term>
- <listitem>
- <para>The TCP port number of the Guacamole proxy daemon
- (<package>guacd</package>) which should be used for this connection.
- If <constant>NULL</constant>, the value defined with the
- <property>guacd-port</property> property in
- <filename>guacamole.properties</filename> will be used.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>proxy_encryption_method</property></term>
- <listitem>
- <para>The encryption method which should be used when communicating with the
- Guacamole proxy daemon (<package>guacd</package>) for this connection.
- This can be either <constant>NONE</constant>, for no encryption, or
- <constant>SSL</constant>, for SSL/TLS. If <constant>NULL</constant>,
- the encryption method will be dictated by the
- <property>guacd-ssl</property> property in
- <filename>guacamole.properties</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>connection_weight</property></term>
- <listitem>
- <para>The weight for a connection, used for applying weighted load balancing
- algorithms when connections are part of a BALANCING group. This is an
- integer value, where values <constant>1</constant> or greater will weight
- the connection relative to other connections in that group, and values
- below <constant>1</constant> cause the connection to be disabled in the
- group. If <constant>NULL</constant>, the connection will be assigned a
- default weight of <constant>1</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>failover_only</property></term>
- <listitem>
- <para>Whether this connection should be used for failover situations only,
- also known as a "hot spare". If this column is set to
- <constant>TRUE</constant> or <constant>1</constant>, this connection
- will be used only when another connection within the same
- <type>BALANCING</type> connection group has failed due to an error
- within the remote desktop. </para>
- <para><emphasis>Connection groups will always transparently switch to the
- next available connection in the event of remote desktop failure,
- regardless of the value of this column.</emphasis> This column
- simply dictates whether a particular connection should be
- <emphasis>reserved</emphasis> for such situations, and left unused
- otherwise.</para>
- <para>This column only has an effect on connections within
- <type>BALANCING</type> groups.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>As there are potentially multiple parameters per connection, where the names of
- each parameter are completely arbitrary and determined only by the protocol in use,
- every parameter for a given connection has an entry in table
- <classname>guacamole_connection_parameter</classname> table associated with its
- corresponding connection. This table contains the following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>connection_id</property></term>
- <listitem>
- <para>The <property>connection_id</property> value from the connection this
- parameter is for.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>parameter_name</property></term>
- <listitem>
- <para>The name of the parameter to set. This is the name listed in the
- documentation for the protocol specified in the associated
- connection.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>parameter_value</property></term>
- <listitem>
- <para>The value to assign to the parameter named. While this value is an
- arbitrary string, it must conform to the requirements of the protocol as
- documented for the connection to be successful.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Adding a connection and corresponding parameters is relatively easy compared to
- adding a user as there is no salt to generate nor password to hash:</para>
- <informalexample>
- <programlisting>-- Create connection
-INSERT INTO guacamole_connection (connection_name, protocol) VALUES ('<replaceable>test</replaceable>', '<replaceable>vnc</replaceable>');
-
--- Determine the connection_id
-SELECT * FROM guacamole_connection WHERE connection_name = '<replaceable>test</replaceable>' AND parent_id IS NULL;
-
--- Add parameters to the new connection
-INSERT INTO guacamole_connection_parameter VALUES (<replaceable>1</replaceable>, 'hostname', '<replaceable>localhost</replaceable>');
-INSERT INTO guacamole_connection_parameter VALUES (<replaceable>1</replaceable>, 'port', '<replaceable>5901</replaceable>');</programlisting>
- </informalexample>
- <section xml:id="jdbc-auth-schema-connection-history">
- <title>Usage history</title>
- <indexterm>
- <primary><classname>guacamole_connection_history</classname></primary>
- </indexterm>
- <para>When a connection is initiated or terminated, a corresponding entry in the
- <classname>guacamole_connection_history</classname> table is created or
- updated respectively. Each entry is associated with the user using the
- connection, the connection itself, the <link
- linkend="jdbc-auth-schema-sharing-profiles">sharing profile</link> in use
- (if the connection is being shared), and the time the connection started. If the
- connection has ended, the end time is also stored.</para>
- <para>It is very unlikely that a user will need to update this table, but knowing
- the structure is potentially useful if you wish to generate a report of
- Guacamole usage. The <classname>guacamole_connection_history</classname> table
- has the following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>history_id</property></term>
- <listitem>
- <para>The unique integer associated with each history record. This value
- is generated automatically when a new entry is inserted into the
- <classname>guacamole_connection_history</classname>
- table.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>user_id</property></term>
- <listitem>
- <para>The value of the <property>user_id</property> from the entry in
- <classname>guacamole_user</classname> associated with the user
- using the connection. If the user no longer exists, this will be
- <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>username</property></term>
- <listitem>
- <para>The username associated with the user at the time that they used
- the connection. This username value is not guaranteed to uniquely
- identify a user, as the original user may be subsequently renamed or
- deleted.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>connection_id</property></term>
- <listitem>
- <para>The value of the <property>connection_id</property> from the entry
- in <classname>guacamole_connection</classname> associated the
- connection being used. If the connection associated with the history
- record no longer exists, this will be
- <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>connection_name</property></term>
- <listitem>
- <para>The name associated with the connection at the time that it was
- used.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>sharing_profile_id</property></term>
- <listitem>
- <para>The value of the <property>sharing_profile_id</property> from the
- entry in <classname>guacamole_sharing_profile</classname> associated
- the sharing profile being used to access the connection. If the
- connection is not being shared (no sharing profile is being used),
- or if the sharing profile associated with the history record no
- longer exists, this will be <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>sharing_profile_name</property></term>
- <listitem>
- <para>The name associated with the sharing profile being used to access
- the connection at the time this history entry was recorded. If the
- connection is not being shared, this will be
- <constant>NULL</constant>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>start_date</property></term>
- <listitem>
- <para>The time at which the connection was started by the user
- specified. Despite its name, this column also stores time
- information in addition to the date.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>end_date</property></term>
- <listitem>
- <para>The time at which the connection ended. If the connection is still
- active, the value in this column will be <constant>NULL</constant>.
- Despite its name, this column also stores time information in
- addition to the date.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </section>
- <section xml:id="jdbc-auth-schema-sharing-profiles">
- <title>Sharing profiles and parameters</title>
- <indexterm>
- <primary><classname>guacamole_sharing_profile</classname></primary>
- </indexterm>
- <indexterm>
- <primary><classname>guacamole_sharing_profile_parameter</classname></primary>
- </indexterm>
- <para>Each sharing profile has an entry in the
- <classname>guacamole_sharing_profile</classname> table, with a one-to-many
- relationship to parameters, stored as name/value pairs in the
- <classname>guacamole_sharing_profile_parameter</classname> table.</para>
- <para>The <classname>guacamole_sharing_profile</classname> table is simply a pairing of
- a unique and descriptive name with the connection that can be shared using the
- sharing profile, also known as the "primary connection". It contains the following
- columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>sharing_profile_id</property></term>
- <listitem>
- <para>The unique integer associated with each sharing profile. This value is
- generated automatically when a new entry is inserted into the
- <classname>guacamole_sharing_profile</classname> table.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>sharing_profile_name</property></term>
- <listitem>
- <para>The unique name associated with each sharing profile. This value must
- be specified manually, and must be different from any existing sharing
- profile name associated with the same primary connection. References to
- sharing profiles in other tables use the value from
- <property>sharing_profile_id</property>, not
- <property>sharing_profile_name</property>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>primary_connection_id</property></term>
- <listitem>
- <para>The unique integer associated with the primary connection. The
- "primary connection" is the connection which can be shared using this
- sharing profile.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>As there are potentially multiple parameters per sharing profile, where the names
- of each parameter are completely arbitrary and determined only by the protocol
- associated with the primary connection, every parameter for a given sharing profile
- has an entry in the <classname>guacamole_sharing_profile_parameter</classname> table
- associated with its corresponding sharing profile. This table contains the following
- columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>sharing_profile_id</property></term>
- <listitem>
- <para>The <property>sharing_profile_id</property> value from the entry in
- the <classname>guacamole_sharing_profile</classname> table for the
- sharing profile this parameter applies to.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>parameter_name</property></term>
- <listitem>
- <para>The name of the parameter to set. This is the name listed in the
- documentation for the protocol of the primary connection of the
- associated sharing profile.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>parameter_value</property></term>
- <listitem>
- <para>The value to assign to the parameter named. While this value is an
- arbitrary string, it must conform to the requirements of the protocol as
- documented.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="jdbc-auth-schema-connection-groups">
- <title>Connection groups</title>
- <indexterm>
- <primary><classname>guacamole_connection_group</classname></primary>
- </indexterm>
- <para>Each connection group has an entry in the
- <classname>guacamole_connection_group</classname> table, with a one-to-many
- relationship to other groups and connections.</para>
- <para>The <classname>guacamole_connection_group</classname> table is simply a pairing of
- a unique and descriptive name with a group type, which can be either
- <type>ORGANIZATIONAL</type> or <type>BALANCING</type>. It contains the following
- columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>connection_group_id</property></term>
- <listitem>
- <para>The unique integer associated with each connection group. This value
- is generated automatically when a new entry is inserted into the
- <classname>guacamole_connection_group</classname> table.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>connection_group_name</property></term>
- <listitem>
- <para>The unique name associated with each connection group. This value must
- be specified manually, and must be different from any existing
- connection group name in the same connection group. References to
- connections in other tables use the value from
- <property>connection_group_id</property>, not
- <property>connection_group_name</property>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>type</property></term>
- <listitem>
- <para>The type of this connection group. This can be either
- <type>ORGANIZATIONAL</type> or <type>BALANCING</type>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>parent_id</property></term>
- <listitem>
- <para>The unique integer associated with the connection group containing
- this connection group, or <constant>NULL</constant> if this connection
- group is within the root group.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>max_connections</property></term>
- <listitem>
- <para>The maximum number of concurrent connections to allow to this
- connection group at any one time <emphasis>regardless of
- user</emphasis>. <constant>NULL</constant> will use the default value
- specified in <filename>guacamole.properties</filename> with the
- <property>mysql-default-max-connections</property> or
- <property>postgresql-default-max-connections</property> properties,
- and a value of <constant>0</constant> denotes unlimited. This only has
- an effect on <type>BALANCING</type> groups.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>max_connections_per_user</property></term>
- <listitem>
- <para>The maximum number of concurrent connections to allow to this
- connection group at any one time <emphasis>from a single
- user</emphasis>. <constant>NULL</constant> will use the default value
- specified in <filename>guacamole.properties</filename> with the
- <property>mysql-default-max-connections</property> or
- <property>postgresql-default-max-connections</property> properties,
- and a value of <constant>0</constant> denotes unlimited. This only has
- an effect on <type>BALANCING</type> groups.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>enable_session_affinity</property></term>
- <listitem>
- <para>Whether session affinity should apply to this connection group. If
- this column is set to <constant>TRUE</constant> or
- <constant>1</constant>, users will be consistently routed to the
- same underlying connection until they log out. The normal balancing
- behavior will only apply for each user's first connection attempt during
- any one Guacamole session. By default, session affinity is not enabled,
- and connections will always be balanced across the entire connection
- group. This only has an effect on <type>BALANCING</type> groups.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Adding a connection group is even simpler than adding a new connection as there
- are no associated parameters stored in a separate table:</para>
- <informalexample>
- <programlisting>-- Create connection group
-INSERT INTO guacamole_connection_group (connection_group_name, type)
- VALUES ('<replaceable>test</replaceable>', '<replaceable>ORGANIZATIONAL</replaceable>');</programlisting>
- </informalexample>
- </section>
- <section xml:id="jdbc-auth-schema-permissions">
- <title>Permissions</title>
- <para>There are several permissions tables in the schema which correspond to the types
- of permissions in Guacamole's authentication model: system permissions, which
- control operations that affect the system as a whole, and permissions which control
- operations that affect specific objects within the system, such as users,
- connections, or groups.</para>
- <section xml:id="jdbc-auth-schema-system-permissions">
- <title>lSystem permissions</title>
- <indexterm>
- <primary><classname>guacamole_system_permission</classname></primary>
- </indexterm>
- <para>System permissions are defined by entries in the
- <classname>guacamole_system_permission</classname> table. Each entry grants
- permission for a specific user or user group to perform a specific system
- operation.</para>
- <para>The <classname>guacamole_system_permission</classname> table contains the
- following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>entity_id</property></term>
- <listitem>
- <para>The value of the <property>entity_id</property> column of the
- entry associated with the user or user group owning this
- permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>permission</property></term>
- <listitem>
- <para>The permission being granted. This column can have one of six
- possible values: <constant>ADMINISTER</constant>, which grants the
- ability to administer the entire system (essentially a wildcard
- permission), <constant>CREATE_CONNECTION</constant>, which grants
- the ability to create connections,
- <constant>CREATE_CONNECTION_GROUP</constant>, which grants the
- ability to create connections groups,
- <constant>CREATE_SHARING_PROFILE</constant>, which grants the
- ability to create sharing profiles,
- <constant>CREATE_USER</constant>, which grants the ability to create
- users, or <constant>CREATE_USER_GROUP</constant>, which grants the
- ability to create user groups.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="jdbc-auth-schema-user-permissions">
- <title>User permissions</title>
- <indexterm>
- <primary><classname>guacamole_user_permission</classname></primary>
- </indexterm>
- <para>User permissions are defined by entries in the
- <classname>guacamole_user_permission</classname> table. Each entry grants
- permission for a specific user or user group to perform a specific operation on
- an existing user.</para>
- <para>The <classname>guacamole_user_permission</classname> table contains the
- following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>entity_id</property></term>
- <listitem>
- <para>The value of the <property>entity_id</property> column of the
- entry associated with the user or user group owning this
- permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>affected_user_id</property></term>
- <listitem>
- <para>The value of the <property>user_id</property> column of the entry
- associated with the user <emphasis>affected</emphasis> by this
- permission. This is the user that would be the object of the
- operation represented by this permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>permission</property></term>
- <listitem>
- <para>The permission being granted. This column can have one of four
- possible values: <constant>ADMINISTER</constant>, which grants the
- ability to add or remove permissions which affect the user,
- <constant>READ</constant>, which grants the ability to read data
- associated with the user, <constant>UPDATE</constant>, which grants
- the ability to update data associated with the user, or
- <constant>DELETE</constant>, which grants the ability to delete
- the user.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="jdbc-auth-schema-group-permissions">
- <title>User group permissions</title>
- <indexterm>
- <primary><classname>guacamole_user_group_permission</classname></primary>
- </indexterm>
- <para>User group permissions are defined by entries in the
- <classname>guacamole_user_group_permission</classname> table. Each entry
- grants permission for a specific user or user group to perform a specific
- operation on an existing user group.</para>
- <para>The <classname>guacamole_user_group_permission</classname> table contains the
- following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>entity_id</property></term>
- <listitem>
- <para>The value of the <property>entity_id</property> column of the
- entry associated with the user or user group owning this
- permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>affected_user_group_id</property></term>
- <listitem>
- <para>The value of the <property>user_group_id</property> column of the
- entry associated with the user group <emphasis>affected</emphasis>
- by this permission. This is the user group that would be the object
- of the operation represented by this permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>permission</property></term>
- <listitem>
- <para>The permission being granted. This column can have one of four
- possible values: <constant>ADMINISTER</constant>, which grants the
- ability to add or remove permissions which affect the user group,
- <constant>READ</constant>, which grants the ability to read data
- associated with the user group, <constant>UPDATE</constant>, which
- grants the ability to update data associated with the user group, or
- <constant>DELETE</constant>, which grants the ability to delete
- the user group.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="jdbc-auth-schema-connection-permissions">
- <title>Connection permissions</title>
- <indexterm>
- <primary><classname>guacamole_connection_permission</classname></primary>
- </indexterm>
- <para>Connection permissions are defined by entries in the
- <classname>guacamole_connection_permission</classname> table. Each entry
- grants permission for a specific user or user group to perform a specific
- operation on an existing connection.</para>
- <para>The <classname>guacamole_connection_permission</classname> table contains the
- following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>entity_id</property></term>
- <listitem>
- <para>The value of the <property>entity_id</property> column of the
- entry associated with the user or user group owning this
- permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>connection_id</property></term>
- <listitem>
- <para>The value of the <property>connection_id</property> column of the
- entry associated with the connection affected by this permission.
- This is the connection that would be the object of the operation
- represented by this permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>permission</property></term>
- <listitem>
- <para>The permission being granted. This column can have one of four
- possible values: <constant>ADMINISTER</constant>, which grants the
- ability to add or remove permissions which affect the connection,
- <constant>READ</constant>, which grants the ability to read data
- associated with the connection (a prerequisite for connecting),
- <constant>UPDATE</constant>, which grants the ability to update
- data associated with the connection, or <constant>DELETE</constant>,
- which grants the ability to delete the connection.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="jdbc-auth-schema-sharing-profile-permissions">
- <title>Sharing profile permissions</title>
- <indexterm>
- <primary><classname>guacamole_sharing_profile_permission</classname></primary>
- </indexterm>
- <para>Sharing profile permissions are defined by entries in the
- <classname>guacamole_sharing_profile_permission</classname> table. Each
- entry grants permission for a specific user or user group to perform a specific
- operation on an existing sharing profile.</para>
- <para>The <classname>guacamole_sharing_profile_permission</classname> table contains
- the following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>entity_id</property></term>
- <listitem>
- <para>The value of the <property>entity_id</property> column of the
- entry associated with the user or user group owning this
- permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>sharing_profile_id</property></term>
- <listitem>
- <para>The value of the <property>sharing_profile_id</property> column of
- the entry associated with the sharing profile affected by this
- permission. This is the sharing profile that would be the object of
- the operation represented by this permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>permission</property></term>
- <listitem>
- <para>The permission being granted. This column can have one of four
- possible values: <constant>ADMINISTER</constant>, which grants the
- ability to add or remove permissions which affect the sharing
- profile, <constant>READ</constant>, which grants the ability to read
- data associated with the sharing profile (a prerequisite for using
- the sharing profile to share an active connection),
- <constant>UPDATE</constant>, which grants the ability to update
- data associated with the sharing profile, or
- <constant>DELETE</constant>, which grants the ability to delete
- the sharing profile.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="jdbc-auth-schema-connection-group-permissions">
- <title>Connection group permissions</title>
- <indexterm>
- <primary><classname>guacamole_connection_group_permission</classname></primary>
- </indexterm>
- <para>Connection group permissions are defined by entries in the
- <classname>guacamole_connection_group_permission</classname> table. Each
- entry grants permission for a specific user or user group to perform a specific
- operation on an existing connection group.</para>
- <para>The <classname>guacamole_connection_group_permission</classname> table
- contains the following columns:</para>
- <variablelist>
- <varlistentry>
- <term><property>entity_id</property></term>
- <listitem>
- <para>The value of the <property>entity_id</property> column of the
- entry associated with the user or user group owning this
- permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>connection_group_id</property></term>
- <listitem>
- <para>The value of the <property>connection_group_id</property> column
- of the entry associated with the connection group affected by this
- permission. This is the connection group that would be the object of
- the operation represented by this permission.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>permission</property></term>
- <listitem>
- <para>The permission being granted. This column can have one of four
- possible values: <constant>ADMINISTER</constant>, which grants the
- ability to add or remove permissions which affect the connection
- group, <constant>READ</constant>, which grants the ability to read
- data associated with the connection group,
- <constant>UPDATE</constant>, which grants the ability to update
- data associated with the connection group, or
- <constant>DELETE</constant>, which grants the ability to delete
- the connection group (and implicitly its contents).</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/ldap-auth.xml b/src/chapters/ldap-auth.xml
deleted file mode 100644
index 750d7ea..0000000
--- a/src/chapters/ldap-auth.xml
+++ /dev/null
@@ -1,686 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="ldap-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>LDAP authentication</title>
- <indexterm>
- <primary>LDAP</primary>
- </indexterm>
- <para>Guacamole supports LDAP authentication via an extension available from the main project
- website. This extension allows users and connections to be stored directly within an LDAP
- directory. If you have a centralized authentication system that uses LDAP, Guacamole's LDAP
- support can be a good way to allow your users to use their existing usernames and passwords
- to log into Guacamole.</para>
- <para>To use the LDAP authentication extension, you will need:</para>
- <orderedlist>
- <listitem>
- <para>An LDAP directory as storage for all authentication data, such as OpenLDAP.</para>
- </listitem>
- <listitem>
- <para>The ability to modify the schema of your LDAP directory.</para>
- </listitem>
- </orderedlist>
- <para>The instructions here assume you already have an LDAP directory installed and working, and
- do not cover the initial setup of such a directory.</para>
- <important>
- <para>This chapter involves modifying the contents of <varname>GUACAMOLE_HOME</varname> -
- the Guacamole configuration directory. If you are unsure where
- <varname>GUACAMOLE_HOME</varname> is located on your system, please consult <xref
- linkend="configuring-guacamole"/> before proceeding.</para>
- </important>
- <section xml:id="ldap-architecture">
- <title>How Guacamole uses LDAP</title>
- <para>If the LDAP extension is installed, Guacamole will authenticate users against your
- LDAP server by attempting a bind as that user. The given username and password will be
- submitted to the LDAP server during the bind attempt.</para>
- <para>If the bind attempt is successful, the set of available Guacamole connections is
- queried from the LDAP directory by executing an LDAP query as the bound user. Each
- Guacamole connection is represented within the directory as a special type of group:
- <classname>guacConfigGroup</classname>. Attributes associated with the group define
- the protocol and parameters of the connection, and users are allowed access to the
- connection only if they are associated with that group.</para>
- <para>This architecture has a number of benefits:</para>
- <orderedlist>
- <listitem>
- <para>Your users can use their existing usernames and passwords to log into
- Guacamole.</para>
- </listitem>
- <listitem>
- <para>You can manage Guacamole connections using the same tool that you already use
- to manage your LDAP directory, such as <link
- xlink:href="https://directory.apache.org/studio/">Apache Directory
- Studio</link>.</para>
- </listitem>
- <listitem>
- <para>Existing security restrictions can limit visibility/accessibility of Guacamole
- connections.</para>
- </listitem>
- <listitem>
- <para>Access to connections can easily be granted and revoked, as each connection is
- represented by a group.</para>
- </listitem>
- </orderedlist>
- <important>
- <para>Though Guacamole connections can be stored within the LDAP directory, this is not
- required. Connection data can alternatively be stored within a database like MySQL
- or PostgreSQL as long as the LDAP username matches the username of the database
- user. Configuring Guacamole to use a database for authentication or connection
- storage is covered in <xref linkend="jdbc-auth"/> and later in this chapter in <xref
- linkend="ldap-and-database"/>.</para>
- </important>
- </section>
- <section xml:id="ldap-downloading">
- <title>Downloading the LDAP extension</title>
- <para>The LDAP authentication extension is available separately from the main
- <filename>guacamole.war</filename>. The link for this and all other
- officially-supported and compatible extensions for a particular version of Guacamole are
- provided on the release notes for that version. You can find the release notes for
- current versions of Guacamole here: <link
- xlink:href="http://guacamole.apache.org/releases/"
- >http://guacamole.apache.org/releases/</link>.</para>
- <para>The LDAP authentication extension is packaged as a <filename>.tar.gz</filename> file
- containing:</para>
- <variablelist>
- <varlistentry>
- <term><filename>guacamole-auth-ldap-1.3.0.jar</filename></term>
- <listitem>
- <para>The Guacamole LDAP support extension itself, which must be placed in
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>schema/</filename></term>
- <listitem>
- <para>LDAP schema files. An <filename>.ldif</filename> file compatible with
- OpenLDAP is provided, as well as a <filename>.schema</filename> file
- compliant with RFC-2252. The <filename>.schema</filename> file can be
- transformed into the <filename>.ldif</filename> file automatically.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="ldap-schema-changes">
- <title>Preparing your LDAP directory (optional)</title>
- <para>Although your LDAP directory already provides a means of storing and authenticating
- users, Guacamole also needs storage of connection configuration data, such as hostnames
- and ports, and a means of associating users with connections that they should have
- access to. You can do this either through modifying the LDAP directory schema, or
- through using a database like MySQL or PostgreSQL. If you do not wish to use the LDAP
- directory for connection storage, skip ahead to <xref linkend="ldap-and-database"
- />.</para>
- <para>If you wish to store connection data directly within the LDAP directory, the required
- modifications to the LDAP schema are made through applying one of the provided schema
- files. These schema files define an additional object class,
- <classname>guacConfigGroup</classname>, which contains all configuration information
- for a particular connection, and can be associated with arbitrarily-many users and
- groups. Each connection defined by a <classname>guacConfigGroup</classname> will be
- accessible only by users who are members of that group (specified with the
- <property>member</property> attribute), or who are members of associated groups
- (specified with the <property>seeAlso</property> attribute).</para>
- <important>
- <para>The instructions given for applying the Guacamole LDAP schema changes are specific
- to OpenLDAP, but other LDAP implementations, including Active Directory, will have
- their own methods for updating the schema.</para>
- <para>If you are not using OpenLDAP, a standards-compliant schema file is provided that
- can be used to update the schema of any LDAP directory supporting RFC-2252. Please
- consult the documentation of your LDAP directory to determine how such schema
- changes can be applied.</para>
- </important>
- <para>The schema files are located within the <filename>schema/</filename> directory of the
- archive containing the LDAP extension. You will only need one of these files:</para>
- <variablelist>
- <varlistentry>
- <term><filename>guacConfigGroup.schema</filename></term>
- <listitem>
- <para>A standards-compliant file describing the schema. This file can be used
- with any LDAP directory compliant with RFC-2252.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>guacConfigGroup.ldif</filename></term>
- <listitem>
- <para>An LDIF file compatible with OpenLDAP. This file was automatically built
- from the provided <filename>.schema</filename> file for convenience.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>This chapter will cover applying <filename>guacConfigGroup.ldif</filename> to an
- OpenLDAP server. If you are not using OpenLDAP, your LDAP server should provide
- documentation for modifying its schema. If this is the case, please consult the
- documentation of your LDAP server before proceeding.</para>
- <section>
- <title>Applying the schema changes to OpenLDAP</title>
- <para>Schema changes to OpenLDAP are applied using the <command>ldapadd</command>
- utility with the provided <filename>guacConfigGroup.ldif</filename> file:</para>
- <informalexample>
- <screen><prompt>#</prompt> <userinput>ldapadd -Q -Y EXTERNAL -H ldapi:/// -f schema/guacConfigGroup.ldif</userinput>
-<computeroutput>adding new entry "cn=guacConfigGroup,cn=schema,cn=config"
-</computeroutput>
-<prompt>#</prompt></screen>
- </informalexample>
- <para>If the <classname>guacConfigGroup</classname> object was added successfully, you
- should see output as above. You can confirm the presence of the new object class
- using <command>ldapsearch</command>:</para>
- <informalexample>
- <screen><prompt>#</prompt> <userinput>ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config dn</userinput>
-<computeroutput>dn: cn=schema,cn=config
-
-dn: cn={0}core,cn=schema,cn=config
-
-dn: cn={1}cosine,cn=schema,cn=config
-
-dn: cn={2}nis,cn=schema,cn=config
-
-dn: cn={3}inetorgperson,cn=schema,cn=config
-
-dn: cn={4}guacConfigGroup,cn=schema,cn=config
-</computeroutput>
-<prompt>#</prompt></screen>
- </informalexample>
- </section>
- </section>
- <section xml:id="ldap-and-database">
- <title>Associating LDAP with a database</title>
- <para>If you install both the LDAP authentication as well as support for a database
- (following the instructions in <xref linkend="jdbc-auth"/>), Guacamole will
- automatically attempt to authenticate against both systems whenever a user attempts to
- log in. In addition to any visible objects within the LDAP directory, that user will
- have access to any data associated with their account in the database, as well as any
- data associated with user groups that they belong to. LDAP user accounts and groups will
- be considered equivalent to database users and groups if their unique names are
- identical, as determined by the attributes given for <link linkend="guac-ldap-config"
- >the <property>ldap-username-attribute</property> and
- <property>ldap-group-name-attribute</property> properties</link>.</para>
- <para>Data can be manually associated with LDAP user accounts or groups by creating
- corresponding users or groups within the database which each have the same names. As
- long as the names are identical, a successful login attempt against LDAP will be trusted
- by the database authentication, and that user's associated data will be visible.</para>
- <para>If an administrator account (such as the default <systemitem>guacadmin</systemitem>
- user provided with the database authentication) has a corresponding user in the LDAP
- directory with permission to read other LDAP users and groups, the Guacamole
- administrative interface will include them in the lists presented to the administrator,
- and will allow connections from the database to be associated with those users or groups
- directly.</para>
- </section>
- <section xml:id="installing-ldap-auth">
- <title>Installing LDAP authentication</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- located within the <filename>GUACAMOLE_HOME/extensions</filename> directory. To install
- the LDAP authentication extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Copy <filename>guacamole-auth-ldap-1.3.0.jar</filename> within
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </step>
- <step>
- <para>Configure Guacamole to use LDAP authentication, as described below.</para>
- </step>
- </procedure>
- <important>
- <para>You will need to restart Guacamole by restarting your servlet container in order
- to complete the installation. Doing this will disconnect all active users, so be
- sure that it is safe to do so prior to attempting installation. If you do not
- configure the LDAP authentication properly, Guacamole will not start up again until
- the configuration is fixed.</para>
- </important>
- <section xml:id="guac-ldap-config">
- <title>Configuring Guacamole for LDAP</title>
- <indexterm>
- <primary>configuring LDAP</primary>
- </indexterm>
- <indexterm>
- <primary>LDAP</primary>
- <secondary>configuration</secondary>
- </indexterm>
- <para>Additional properties may be added to <filename>guacamole.properties</filename> to
- describe how your LDAP directory is organized and how Guacamole should connect (and
- bind) to your LDAP server. Among these properties, only the
- <property>ldap-user-base-dn</property> property is required:</para>
- <variablelist>
- <varlistentry>
- <term><property>ldap-hostname</property></term>
- <listitem>
- <para>The hostname of your LDAP server. If omitted, "localhost" will be used
- by default. You will need to use a different value if your LDAP server
- is located elsewhere.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-port</property></term>
- <listitem>
- <para>The port your LDAP server listens on. If omitted, the standard LDAP or
- LDAPS port will be used, depending on the encryption method specified
- with <property>ldap-encryption-method</property> (if any). Unencrypted
- LDAP uses the standard port of 389, while LDAPS uses port 636. Unless
- you manually configured your LDAP server to do otherwise, your LDAP
- server probably listens on port 389.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-encryption-method</property></term>
- <listitem>
- <para>The encryption mechanism that Guacamole should use when communicating
- with your LDAP server. Legal values are "none" for unencrypted LDAP,
- "ssl" for LDAP over SSL/TLS (commonly known as LDAPS), or "starttls" for
- STARTTLS. If omitted, encryption will not be used.</para>
- <para>If you do use encryption when connecting to your LDAP server, you will
- need to ensure that its certificate chain can be verified using the
- certificates in Java's trust store, often referred to as
- <filename>cacerts</filename>. If this is not the case, you will need
- to use Java's <command>keytool</command> utility to either add the
- necessary certificates or to create a new trust store containing those
- certificates.</para>
- <para>If you will be using your own trust store and not the default
- <filename>cacerts</filename>, you will need to specify the full path
- to that trust store using the system property
- <property>javax.net.ssl.trustStore</property>. Note that this is a
- system property and <emphasis>not</emphasis> a Guacamole property; it
- must be specified when starting the JVM using the <option>-D</option>
- option. Your servlet container will provide some means of specifying
- startup options for the JVM.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-max-search-results</property></term>
- <listitem>
- <para>The maximum number of search results that can be returned by a single
- LDAP query. LDAP queries which exceed this maximum will fail.
- <emphasis>This property is optional.</emphasis> If omitted, each
- LDAP query will be limited to a maximum of 1000 results.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-search-bind-dn</property></term>
- <listitem>
- <para>The DN (Distinguished Name) of the user to bind as when authenticating
- users that are attempting to log in. If specified, Guacamole will query
- the LDAP directory to determine the DN of each user that logs in. If
- omitted, each user's DN will be derived directly using the base DN
- specified with <property>ldap-user-base-dn</property>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-search-bind-password</property></term>
- <listitem>
- <para>The password to provide to the LDAP server when binding as
- <property>ldap-search-bind-dn</property> to authenticate other
- users. This property is only used if
- <property>ldap-search-bind-dn</property> is specified. If omitted,
- but <property>ldap-search-bind-dn</property> is specified, Guacamole
- will attempt to bind with the LDAP server without a password.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-user-base-dn</property></term>
- <listitem>
- <para>The base of the DN for all Guacamole users. <emphasis>This property is
- absolutely required in all cases.</emphasis> All Guacamole users
- must be descendents of this base DN.</para>
- <para>If a search DN is provided (via
- <property>ldap-search-bind-dn</property>), then Guacamole users need
- only be somewhere within the subtree of the specified user base
- DN.</para>
- <para>If a search DN <emphasis>is not</emphasis> provided, then all
- Guacamole users must be <emphasis>direct descendents</emphasis> of this
- base DN, as the base DN will be appended to the username to derive the
- user's DN. For example, if <property>ldap-user-base-dn</property> is
- "<systemitem>ou=people,dc=example,dc=net</systemitem>", and
- <property>ldap-username-attribute</property> is
- "<property>uid</property>", then a person attempting to login as
- "<systemitem>user</systemitem>" would be mapped to the following
- full DN:
- "<systemitem>uid=user,ou=people,dc=example,dc=net</systemitem>".</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-username-attribute</property></term>
- <listitem>
- <para>The attribute or attributes which contain the username within all
- Guacamole user objects in the LDAP directory. Usually, and by default,
- this will simply be "<property>uid</property>". If your LDAP directory
- contains users whose usernames are dictated by different attributes,
- multiple attributes can be specified here, separated by commas, but
- beware: <emphasis>doing so requires that a search DN be provided with
- <property>ldap-search-bind-dn</property></emphasis>.</para>
- <para>If a search DN <emphasis>is not</emphasis> provided, then the single
- username attribute specified here will be used together with the user
- base DN to directly derive the full DN of each user. For example, if
- <property>ldap-user-base-dn</property> is
- "<systemitem>ou=people,dc=example,dc=net</systemitem>", and
- <property>ldap-username-attribute</property> is
- "<property>uid</property>", then a person attempting to login as
- "<systemitem>user</systemitem>" would be mapped to the following
- full DN:
- "<systemitem>uid=user,ou=people,dc=example,dc=net</systemitem>".</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-member-attribute</property></term>
- <listitem>
- <para>The attribute which contains the members within all group objects in the
- LDAP directory. Usually, and by default, this will simply be
- "<property>member</property>". If your LDAP directory contains groups
- whose members are dictated by a different attribute, it can be specified
- here.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-member-attribute-type</property></term>
- <listitem>
- <para>Specify whether the attribute defined in
- "<property>ldap-member-attribute</property>" (Usually
- "<property>member</property>") identifies a group member by DN or by
- usercode. Possible values: "<property>dn</property>" (the default, if
- not specified) or "<property>uid</property>".</para>
- <para>Example: an LDAP server may present groups using the
- <classname>groupOfNames</classname> scheme
- <informalexample>
- <programlisting>dn: cn=group1,ou=Groups,dc=example,dc=net
-objectClass: groupOfNames
-cn: group1
-gidNumber: 12345
-member: user1,ou=People,dc=example,dc=net
-member: user2,ou=People,dc=example,dc=net</programlisting>
- </informalexample>
- <property>ldap-member-attribute</property> is
- <systemitem>member</systemitem> and
- <property>ldap-member-attribute-type</property> is
- <systemitem>dn</systemitem></para>
- <para>Example: an LDAP server may present groups using the
- <classname>posixGroup</classname> scheme
- <informalexample>
- <programlisting>dn: cn=group1,ou=Groups,dc=example,dc=net
-objectClass: posixGroup
-cn: group1
-gidNumber: 12345
-memberUid: user1
-memberUid: user2</programlisting>
- </informalexample>
- <property>ldap-member-attribute</property> is
- <systemitem>memberUid</systemitem> and
- <property>ldap-member-attribute-type</property> is
- <systemitem>uid</systemitem></para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-user-attributes</property></term>
- <listitem>
- <para>The attribute or attributes to retrieve from the LDAP directory for
- the currently logged-in user, separated by commas. If specified, the
- attributes listed here are retrieved from each authenticated user and
- dynamically applied to the parameters of that user's connections as
- <link linkend="parameter-tokens">parameter tokens</link> with the
- prefix "<varname>LDAP_</varname>".</para>
- <para>When a user authenticates with LDAP and accesses a particular
- Guacamole connection, the values of these tokens will be the values of
- their corresponding attributes at the time of authentication. If the
- attribute has no value for the current user, then the corresponding
- token is not applied. If the attribute has multiple values, then the
- first value of the attribute is used.</para>
- <para>When converting an LDAP attribute name into a parameter token name,
- the name of the attribute is transformed into uppercase with each word
- separated by underscores, a naming convention referred to as "uppercase
- with underscores" or "<link
- xlink:href="https://en.wikipedia.org/wiki/Naming_convention_(programming)#Multiple-word_identifiers"
- >screaming snake case</link>". For example:</para>
- <table frame="all">
- <title>Example LDAP attribute / parameter token conversions</title>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1.0*"/>
- <colspec colname="c2" colnum="2" colwidth="1.0*"/>
- <thead>
- <row>
- <entry>LDAP Attribute</entry>
- <entry>Parameter Token</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><varname>lowercase-with-dashes</varname></entry>
- <entry><varname>${LDAP_LOWERCASE_WITH_DASHES}</varname></entry>
- </row>
- <row>
- <entry><varname>CamelCase</varname></entry>
- <entry><varname>${LDAP_CAMEL_CASE}</varname></entry>
- </row>
- <row>
- <entry><varname>headlessCamelCase</varname></entry>
- <entry><varname>${LDAP_HEADLESS_CAMEL_CASE}</varname></entry>
- </row>
- <row>
- <entry><varname>lettersAndNumbers1234</varname></entry>
- <entry><varname>${LDAP_LETTERS_AND_NUMBERS_1234}</varname></entry>
- </row>
- <row>
- <entry><varname>aRANDOM_mixOf-3NAMINGConventions</varname></entry>
- <entry><varname>${LDAP_A_RANDOM_MIX_OF_3_NAMING_CONVENTIONS}</varname></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>Usage of parameter tokens is discussed in more detail in <xref
- linkend="configuring-guacamole"/> in <xref
- linkend="parameter-tokens"/>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-user-search-filter</property></term>
- <listitem>
- <para>The search filter used to query the LDAP tree for users that can log
- into and be granted privileges in Guacamole. <emphasis>If this property
- is omitted the default of "(objectClass=*)" will be used.
- </emphasis></para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-config-base-dn</property></term>
- <listitem>
- <para>The base of the DN for all Guacamole configurations. <emphasis>This
- property is optional.</emphasis> If omitted, the configurations of
- Guacamole connections will simply not be queried from the LDAP
- directory. If specified, this base DN will be used when querying the
- configurations accessible by a user once they have successfully logged
- in.</para>
- <para>Each configuration is analogous to a connection. Within Guacamole's
- LDAP support, each configuration functions as a group, having user
- members (via the <property>member</property> attribute) and optionally
- group members (via the <property>seeAlso</property> attribute), where
- each member of a particular configuration group will have access to the
- connection defined by that configuration.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-group-base-dn</property></term>
- <listitem>
- <para>The base of the DN for all user groups that may be used by other
- extensions to define permissions or that may referenced within Guacamole
- configurations using the standard <property>seeAlso</property>
- attribute. All groups which will be used to control access to Guacamole
- configurations must be descendents of this base DN. <emphasis>If this
- property is omitted, the <property>seeAlso</property> attribute will
- have no effect on Guacamole configurations.</emphasis></para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-group-name-attribute</property></term>
- <listitem>
- <para>The attribute or attributes which define the unique name of user
- groups in the LDAP directory. Usually, and by default, this will simply
- be "<property>cn</property>". If your LDAP directory contains groups
- whose names are dictated by different attributes, multiple attributes
- can be specified here, separated by commas.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-dereference-aliases</property></term>
- <listitem>
- <para>Controls whether or not the LDAP connection follows (dereferences)
- aliases as it searches the tree. Possible values for this property are
- "never" (the default) so that aliases will never be followed,
- "searching" to dereference during search operations after the base
- object is located, "finding" to dereference in order to locate the
- search base, but not during the actual search, and "always" to always
- dereference aliases.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-follow-referrals</property></term>
- <listitem>
- <para>This option controls whether or not the LDAP module follow referrals
- when processing search results from a LDAP search. Referrals can be
- pointers to other parts of an LDAP tree, or to a different
- server/connection altogether. This is a boolean parameter, with valid
- options of "true" or "false." The default is false. When disabled, LDAP
- referrals will be ignored when encounterd by the Guacamole LDAP client
- and the client will move on to the next result. When enabled, the LDAP
- client will follow the referral and process results within the referral,
- subject to the maximum hops parameter below.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-max-referral-hops</property></term>
- <listitem>
- <para>This option controls the maximum number of referrals that will be
- processed before the LDAP client refuses to follow any more referrals.
- The default is 5. If the ldap-follow-referrals property is set to false
- (the default), this option has no effect. If the ldap-follow-referrals
- option is set to true, this will limit the depth of referrals followed
- to the number specified.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>ldap-operation-timeout</property></term>
- <listitem>
- <para>This option sets the timeout, in seconds, of any single LDAP
- operation. The default is 30 seconds. When this timeout is reached LDAP
- operations will be aborted.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Again, even if the defaults are sufficient for the other properties, <emphasis>you
- must still specify the <property>ldap-user-base-dn</property>
- property</emphasis>. An absolutely minimal configuration for LDAP authentication
- will look like the following:</para>
- <programlisting># LDAP properties
-ldap-user-base-dn: <replaceable>ou=people,dc=example,dc=net</replaceable></programlisting>
- </section>
- <section>
- <title>Completing the installation</title>
- <para>Guacamole will only reread <filename>guacamole.properties</filename> and load
- newly-installed extensions during startup, so your servlet container will need to be
- restarted before the LDAP authentication will take effect. Restart your servlet
- container and give the new authentication a try.</para>
- <para>
- <important>
- <para>You only need to restart your servlet container. <emphasis>You do not need
- to restart <package>guacd</package></emphasis>.</para>
- <para><package>guacd</package> is completely independent of the web application
- and does not deal with <filename>guacamole.properties</filename> or the
- authentication system in any way. Since you are already restarting the
- servlet container, restarting <package>guacd</package> as well technically
- won't hurt anything, but doing so is completely pointless.</para>
- </important>
- </para>
- <para>If Guacamole does not come back online after restarting your servlet container,
- check the logs. Problems in the configuration of the LDAP extension will prevent
- Guacamole from starting up, and any such errors will be recorded in the logs of your
- servlet container. If properly configured, you will be able to log in as any user
- within the defined <property>ldap-user-base-dn</property>.</para>
- </section>
- </section>
- <section xml:id="ldap-auth-schema">
- <title>The LDAP schema</title>
- <indexterm>
- <primary>schema</primary>
- </indexterm>
- <para>Guacamole's LDAP support allows users and connections to be managed purely within an
- LDAP directory defined in <filename>guacamole.properties</filename>. This is
- accomplished with a minimum of changes to the standard LDAP schema - all Guacamole users
- are traditional LDAP users and share the same mechanism of authentication. The only new
- type of object required is a representation for Guacamole connections,
- <classname>guacConfigGroup</classname>, which was added to your server's schema
- during the install process above.</para>
- <section>
- <title>Users</title>
- <para>All Guacamole users, as far as the LDAP support is concerned, are LDAP users with
- standard LDAP credentials. When a user signs in to Guacamole, their username and
- password will be used to bind to the LDAP server. If this bind operation is
- successful, the available connections are queried from the directory and the user is
- allowed in.</para>
- </section>
- <section>
- <title>Connections and parameters</title>
- <para>Each connection is represented by an instance of the
- <classname>guacConfigGroup</classname> object class, an extended version of the
- standard LDAP <classname>groupOfNames</classname>, which provides a protocol and set
- of parameters. Only members of the <classname>guacConfigGroup</classname> will have
- access to the corresponding connection.</para>
- <para>The <classname>guacConfigGroup</classname> object class provides two new
- attributes in addition to those provided by
- <classname>groupOfNames</classname>:</para>
- <variablelist>
- <varlistentry>
- <term><property>guacConfigProtocol</property></term>
- <listitem>
- <para>The protocol associated with the connection, such as
- "<constant>vnc</constant>" or "<constant>rdp</constant>". This
- attribute is required for every <classname>guacConfigGroup</classname>
- and can be given only once.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>guacConfigParameter</property></term>
- <listitem>
- <para>The name and value of a parameter for the specified protocol. This is
- given as
- <code><replaceable>name</replaceable>=<replaceable>value</replaceable></code>,
- where "name" is the name of the parameter, as defined by the
- documentation for the protocol specified, and "value" is any allowed
- value for that parameter.</para>
- <para>This attribute can be given multiple times for the same
- connection.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>For example, to create a new VNC connection which connects to "localhost" at port
- 5900, while granting access to <systemitem>user1</systemitem> and
- <systemitem>user2</systemitem>, you could create an <filename>.ldif</filename>
- file like the following:</para>
- <informalexample>
- <programlisting>dn: cn=Example Connection,ou=groups,dc=example,dc=net
-objectClass: guacConfigGroup
-objectClass: groupOfNames
-cn: Example Connection
-guacConfigProtocol: vnc
-guacConfigParameter: hostname=localhost
-guacConfigParameter: port=5900
-guacConfigParameter: password=secret
-member: cn=user1,ou=people,dc=example,dc=net
-member: cn=user2,ou=people,dc=example,dc=net</programlisting>
- </informalexample>
- <para>The new connection can then be created using the <command>ldapadd</command>
- utility:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>ldapadd -x -D <replaceable>cn=admin,dc=example,dc=net</replaceable> -W -f <replaceable>example-connection.ldif</replaceable></userinput>
-<computeroutput>Enter LDAP Password:
-adding new entry "cn=Example Connection,ou=groups,dc=example,dc=net"
-</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>Where <systemitem>cn=admin,dc=example,dc=net</systemitem> is an administrator
- account with permission to create new entries, and
- <filename>example-connection.ldif</filename> is the name of the
- <filename>.ldif</filename> file you just created.</para>
- <para>There is, of course, no need to use only the standard LDAP utilities to create
- connections and users. There are useful graphical environments for manipulating LDAP
- directories, such as <link xlink:href="https://directory.apache.org/studio/">Apache
- Directory Studio</link>, which make many of the tasks given above much
- easier.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/libguac.xml b/src/chapters/libguac.xml
deleted file mode 100644
index ddaa448..0000000
--- a/src/chapters/libguac.xml
+++ /dev/null
@@ -1,428 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="libguac" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>libguac</title>
- <indexterm>
- <primary>API</primary>
- <secondary>C</secondary>
- </indexterm>
- <indexterm>
- <primary>libguac</primary>
- </indexterm>
- <para>The C API for extending and developing with Guacamole is libguac. All
- native components produced by the Guacamole project link with this
- library, and this library provides the common basis for extending the
- native functionality of those native components (by implementing client
- plugins).</para>
- <para>libguac is used mainly for developing client plugins like
- libguac-client-vnc or libguac-client-rdp, or for developing a proxy
- supporting the Guacamole protocol like guacd. This chapter is intended
- to give an overview of how libguac is used, and how to use it for
- general communication with the Guacamole protocol.</para>
- <section xml:id="libguac-error-handling">
- <title>Error handling</title>
- <para>Most functions within libguac handle errors by returning a zero or
- non-zero value, whichever is appropriate for the function at hand.
- If an error is encountered, the <varname>guac_error</varname>
- variable is set appropriately, and
- <varname>guac_error_message</varname> contains a
- statically-allocated human-readable string describing the context of
- the error. These variables intentionally mimic the functionality
- provided by <varname>errno</varname> and
- <filename>errno.h</filename>.</para>
- <para>Both <varname>guac_error</varname> and
- <varname>guac_error_message</varname> are defined within
- <filename>error.h</filename>. A human-readable string describing
- the error indicated by <varname>guac_error</varname> can be
- retrieved using <methodname>guac_status_string()</methodname>, which
- is also statically allocated.</para>
- <para>If functions defined within client plugins set
- <varname>guac_error</varname> and
- <varname>guac_error_message</varname> appropriately when errors
- are encountered, the messages logged to syslog by guacd will be more
- meaningful for both users and developers.</para>
- </section>
- <section xml:id="libguac-client-plugins">
- <title>Client plugins</title>
- <para>Client plugins are libraries which follow specific conventions such that they can be
- loaded dynamically by guacd. All client plugins <emphasis>must</emphasis>:</para>
- <orderedlist>
- <listitem>
- <para>Follow a naming convention, where the name of the library is
- <package>libguac-client-<replaceable>PROTOCOL</replaceable></package>.
- <emphasis>This is necessary for guacd to locate the library for a requested
- protocol.</emphasis></para>
- </listitem>
- <listitem>
- <para>Be linked against libguac, the library used by guacd to handle the Guacamole
- protocol. The structures which are given to functions invoked by guacd are
- defined by libguac, and are expected to be manipulated via the functions
- provided by libguac or as otherwise documented within the structure itself.
- <emphasis>Communication between guacd and client plugins is only possible if
- they share the same core structural and functional definitions provided by
- libguac.</emphasis></para>
- </listitem>
- <listitem>
- <para>Implement the standard entry point for client plugins,
- <methodname>guac_client_init()</methodname>, described in more detail below.
- It is this function which initializes the structures provided by guacd such that
- users can join and interact with the connection.</para>
- </listitem>
- </orderedlist>
- <section xml:id="libguac-lifecycle-entry">
- <title>Entry point</title>
- <para>All client plugins must provide a function named
- <methodname>guac_client_init</methodname> which accepts, as its sole argument, a
- pointer to a <classname>guac_client</classname> structure. This function is similar
- in principle to the <methodname>main()</methodname> function of a C program, and it
- is the responsibility of this function to initialize the provided structure as
- necessary to begin the actual remote desktop connection, allow users to join/leave,
- etc.</para>
- <para>The provided <classname>guac_client</classname> will already have been initialized
- with handlers for logging, the broadcast socket, etc. The absolutely critical pieces
- which must be provided by <methodname>guac_client_init</methodname> are:</para>
- <orderedlist>
- <listitem>
- <para>A handler for users which join the connection
- (<property>join_handler</property>). The join handler is also usually
- the most appropriate place for the actual remote desktop connection to be
- established.</para>
- </listitem>
- <listitem>
- <para>A <constant>NULL</constant>-terminated set of argument names which the
- client plugin accepts, assigned to the <property>args</property> property of
- the given <classname>guac_client</classname>. As the handshake procedure is
- completed for each connecting user, these argument names will be presented
- as part of the handshake, and the values for those arguments will be passed
- to the join handler once the handshake completes.</para>
- </listitem>
- <listitem>
- <para>A handler for users leaving the connection
- (<property>leave_handler</property>), if any cleanup, updates, etc. are
- required.</para>
- </listitem>
- <listitem>
- <para>A handler for freeing the data associated with the
- <classname>guac_client</classname> after the connection has terminated
- (<property>free_handler</property>). If your plugin will allocate any
- data at all, implementing the free handler is necessary to avoid memory
- leaks.</para>
- </listitem>
- </orderedlist>
- <para>If <methodname>guac_client_init</methodname> returns successfully, guacd will
- proceed with allowing the first use to join the connection, and the rest of the
- plugin lifecycle commences.</para>
- </section>
- <section xml:id="libguac-lifecycle-users">
- <title>Joining/leaving a connection</title>
- <para>Whenever a user joins a connection, including the very first user of a connection
- (the user which is establishing the remote desktop connection in the first place),
- the join handler of the <property>guac_client</property> will be invoked. This
- handler is provided with the <classname>guac_user</classname> structure representing
- the user that just joined, along with the arguments provided during the handshake
- procedure:</para>
- <informalexample>
- <programlisting>int join_handler(guac_user* user, int argc, char** argv) {
- /* Synchronize display state, init the user, etc. */
-}
-
-...
-
-/* Within guac_client_init */
-client->join_handler = join_handler;</programlisting>
- </informalexample>
- <para>As the parameters and user information provided during the Guacamole protocol
- handshake are often required to be known before the remote desktop connection can be
- established, the join handler is usually the best place to create a thread which
- establishes the remote desktop connection and updates the display
- accordingly.</para>
- <para>If necessary, the user which first established the connection can be distinguished
- from all other users by the <property>owner</property> flag of
- <classname>guac_user</classname>, which will be set to a non-zero value.</para>
- <para>Once a user has disconnected, the leave handler of
- <classname>guac_client</classname> will be invoked. Just as with the join
- handler, this handler is provided the <classname>guac_user</classname> structure of
- the user that disconnected. The <classname>guac_user</classname> structure will be
- freed immediately after the handler completes:</para>
- <informalexample>
- <programlisting>int leave_handler(guac_user* user) {
- /* Free user-specific data and clean up */
-}
-
-...
-
-/* Within guac_client_init */
-client->leave_handler = leave_handler;</programlisting>
- </informalexample>
- </section>
- <section xml:id="libguac-lifecycle-termination">
- <title>Termination</title>
- <para>Once the last user of a connection has left, guacd will begin freeing resources
- allocated to that connection, invoking the free handler of the
- <classname>guac_client</classname>. At this point, the "leave" handler has been
- invoked for all previous users. All that remains is for the client plugin to free
- any remaining data that it allocated, such that guacd can clean up the rest:</para>
- <informalexample>
- <programlisting>int free_handler(guac_client* client) {
- /* Disconnect, free client-specific data, etc. */
-}
-
-...
-
-/* Within guac_client_init */
-client->free_handler = free_handler;</programlisting>
- </informalexample>
- </section>
- </section>
- <section xml:id="libguac-layers">
- <title>Layers and buffers</title>
- <para>The main operand of all drawing instructions is the layer,
- represented within libguac by the <classname>guac_layer</classname>
- structure. Each <classname>guac_layer</classname> is normally
- allocated using <methodname>guac_client_alloc_layer()</methodname>
- or <methodname>guac_client_alloc_buffer()</methodname>, depending on
- whether a layer or buffer is desired, and freed with
- <methodname>guac_client_free_layer()</methodname> or
- <methodname>guac_client_free_buffer()</methodname>.</para>
- <important>
- <para>Care must be taken to invoke the allocate and free pairs of
- each type of layer correctly.
- <methodname>guac_client_free_layer()</methodname> should
- only be used to free layers allocated with
- <methodname>guac_client_alloc_layer()</methodname>, and
- <methodname>guac_client_free_buffer()</methodname> should
- only be used to free layers allocated with
- <methodname>guac_client_alloc_buffer()</methodname>, all
- called using the same instance of
- <classname>guac_client</classname>.</para>
- <para>If these restrictions are not observed, the effect of invoking
- these functions is undefined.</para>
- </important>
- <para>Using these layer management functions allows you to reuse
- existing layers or buffers after their original purpose has expired,
- thus conserving resources on the client side, as allocation of new
- layers within the remote client is a relatively expensive
- operation.</para>
- <para>It is through layers and buffers that Guacamole provides support
- for hardware-accelerated compositing and cached updates. Creative
- use of layers and buffers leads to efficient updates on the client
- side, which usually translates into speed and responsiveness.</para>
- <para>Regardless of whether you allocate new layers or buffers, there is
- always one layer guaranteed to be present: the default layer,
- represented by libguac as <varname>GUAC_DEFAULT_LAYER</varname>. If
- you only wish to affect to the main display of the connected client
- somehow, this is the layer you want to use as the operand of your
- drawing instruction.</para>
- </section>
- <section xml:id="libguac-streams">
- <title>Streams</title>
- <para>In addition to drawing, the Guacamole protocol supports streaming of arbitrary data.
- The main operand of all streaming instructions is the stream, represented within libguac
- by the <classname>guac_stream</classname> structure. Each
- <classname>guac_stream</classname> exists either at the user or client levels,
- depending on whether the stream is intended to be broadcast to all users or just one,
- and is thus allocated using either <methodname>guac_client_alloc_stream()</methodname>
- or <methodname>guac_user_alloc_stream()</methodname>. Explicitly-allocated streams must
- eventually be freed with <methodname>guac_client_free_stream()</methodname> or
- <methodname>guac_user_free_stream()</methodname>.</para>
- <important>
- <para>Just as with layers, care must be taken to invoke the allocate and free pairs
- correctly for each explicitly-allocated stream.
- <methodname>guac_client_free_stream()</methodname> should only be used to free
- streams allocated with <methodname>guac_client_alloc_stream()</methodname>, and
- <methodname>guac_user_free_stream()</methodname> should only be used to free
- streams allocated with <methodname>guac_user_alloc_stream()</methodname>.</para>
- <para>If these restrictions are not observed, the effect of invoking these functions is
- undefined.</para>
- </important>
- <para>Streams are the means by which data is transmitted for clipboard (via the <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="clipboard-instruction"
- >"clipboard" instruction</link>), audio (via the <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="audio-stream-instruction"
- >"audio" instruction</link>), and even the images which make up typical drawing
- operations (via the <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="img-instruction">"img" instruction</link>). They will either be allocated
- for you, when an inbound stream is received from a user, or allocated manually, when an
- outbound stream needs to be sent to a user. As with <classname>guac_client</classname>
- and <classname>guac_user</classname>, each <classname>guac_stream</classname> has a set
- of handlers which correspond to instructions received related to streams. These
- instructions are documented in more detail in <xref
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="guacamole-protocol-streaming"/>
- and <xref xmlns:xlink="http://www.w3.org/1999/xlink" linkend="protocol-reference"
- />.</para>
- </section>
- <section xml:id="libguac-sending-instructions">
- <title>Sending instructions</title>
- <para>All drawing in Guacamole is accomplished through the sending of instructions to the
- connected client using the Guacamole protocol. The same goes for streaming audio, video,
- or file content. All features and content supported by Guacamole ultimately reduce to
- one or more instructions which are part of the documented protocol.</para>
- <para>Most drawing using libguac is done using Cairo functions on a
- <classname>cairo_surface_t</classname> (see the Cairo API documentation) which is
- later streamed to the client using an <methodname>img</methodname> instruction and
- subsequent <methodname>blob</methodname> instructions, sent via
- <methodname>guac_client_stream_png()</methodname>. Cairo was chosen as a dependency
- of libguac to provide developers an existing and stable means of drawing to image
- buffers which will ultimately be sent as easy-to-digest PNG images.</para>
- <para>The Guacamole protocol also supports drawing primitives similar to
- those present in the Cairo API and HTML5's canvas tag. These
- instructions are documented individually in the Guacamole Protocol
- Reference in a section dedicated to drawing instructions, and like
- all Guacamole protocol instructions, each instruction has a
- corresponding function in libguac following the naming convention
- <methodname>guac_protocol_send_<replaceable>OPCODE</replaceable>()</methodname>.</para>
- <para>Each protocol function takes a <classname>guac_socket</classname> as an argument,
- which is the buffered I/O object used by libguac. For each active connection, there are
- two important types of <classname>guac_socket</classname> instance: the broadcast
- socket, which exists at the client level within the <classname>guac_client</classname>,
- and the per-user socket, which is accessible within each
- <classname>guac_user</classname>. Data sent along the client-level broadcast socket
- will be sent to all connected users beneath that <classname>guac_client</classname>,
- while data sent along a user-level socket will be sent only to that user.</para>
- <para>For example, to send a "size" instruction to all connected users via the client-level
- broadcast socket, you could invoke:</para>
- <informalexample>
- <programlisting>guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, 1024, 768);</programlisting>
- </informalexample>
- <para>Or, if the instruction is only relevant to a particular user, the socket associated
- with that user can be used instead:</para>
- <informalexample>
- <programlisting>guac_protocol_send_size(<emphasis>user</emphasis>->socket, GUAC_DEFAULT_LAYER, 1024, 768);</programlisting>
- </informalexample>
- <para>The sockets provided by libguac are threadsafe at the protocol level. Instructions
- written to a socket by multiple threads are guaranteed to be written atomically with
- respect to that socket.</para>
- </section>
- <section xml:id="libguac-event-handling">
- <title>Event handling</title>
- <para>Generally, as guacd receives instructions from the connected client, it invokes event
- handlers if set within the associated <classname>guac_user</classname> or
- <classname>guac_client</classname>, depending on the nature of the event. Most
- events are user-specific, and thus the event handlers reside within the
- <classname>guac_user</classname> structure, but there are client-specific events as
- well, such as a user joining or leaving the current connection. Event handlers typically
- correspond to Guacamole protocol instructions received over the socket by a connected
- user, which in turn correspond to events which occur on the client side.</para>
- <section xml:id="libguac-key-events">
- <title>Key events</title>
- <para>When keys are pressed or released on the client side, the client sends key
- instructions to the server. These instructions are parsed and handled by calling the
- key event handler installed in the <property>key_handler</property> member of the
- <classname>guac_user</classname>. This key handler is given the keysym of the
- key that was changed, and a boolean value indicating whether the key was pressed or
- released.</para>
- <informalexample>
- <programlisting>int key_handler(guac_user* user, int keysym, int pressed) {
- /* Do something */
-}
-
-...
-
-/* Within the "join" handler of guac_client */
-user->key_handler = key_handler;</programlisting>
- </informalexample>
- </section>
- <section xml:id="libguac-mouse-events">
- <title>Mouse events</title>
- <para>When the mouse is moved, and buttons are pressed or released, the client sends
- mouse instructions to the server. These instructions are parsed and handled by
- calling the mouse event handler installed in the <property>mouse_handler</property>
- member of the <classname>guac_user</classname>. This mouse handler is given the
- current X and Y coordinates of the mouse pointer, as well as a mask indicating which
- buttons are pressed and which are released.</para>
- <informalexample>
- <programlisting>int mouse_handler(guac_user* user, int x, int y, int button_mask) {
- /* Do something */
-}
-
-...
-
-/* Within the "join" handler of guac_client */
-user->mouse_handler = mouse_handler;</programlisting>
- </informalexample>
- <para>The file <filename>client.h</filename> also defines the mask
- of each button for convenience:</para>
- <variablelist>
- <varlistentry>
- <term><constant>GUAC_CLIENT_MOUSE_LEFT</constant></term>
- <listitem>
- <para>The left mouse button, set when pressed.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>GUAC_CLIENT_MOUSE_MIDDLE</constant></term>
- <listitem>
- <para>The middle mouse button, set when pressed.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>GUAC_CLIENT_MOUSE_RIGHT</constant></term>
- <listitem>
- <para>The right mouse button, set when pressed.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>GUAC_CLIENT_MOUSE_UP</constant></term>
- <listitem>
- <para>The button corresponding to one scroll in the
- upwards direction of the mouse scroll wheel, set
- when scrolled.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><constant>GUAC_CLIENT_MOUSE_DOWN</constant></term>
- <listitem>
- <para>The button corresponding to one scroll in the
- downwards direction of the mouse scroll wheel, set
- when scrolled.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="libguac-clipboard-events">
- <title>Clipboard, file, and other stream events</title>
- <para>If a connected user sends data which should be sent to the clipboard of the remote
- desktop, guacd will trigger the clipboard handler installed in the
- <property>clipboard_handler</property> member of the
- <classname>guac_user</classname> associated with that user.</para>
- <informalexample>
- <programlisting>int clipboard_handler(guac_user* user, guac_stream* stream, char* mimetype) {
- /* Do something */
-}
-
-...
-
-/* Within the "join" handler of guac_client */
-user->clipboard_handler = clipboard_handler;</programlisting>
- </informalexample>
- <para>The handler is expected to assign further handlers to the provided
- <classname>guac_stream</classname> as necessary, such that the <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="blob-instruction"
- >"blob"</link> and <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="end-instruction">"end"</link> instructions received along the stream
- can be handled. A similar handler is provided for received files:</para>
- <informalexample>
- <programlisting>int file_handler(guac_user* user, guac_stream* stream,
- char* mimetype, char* filename) {
- /* Do something */
-}
-
-...
-
-/* Within the "join" handler of guac_client */
-user->file_handler = file_handler;</programlisting>
- </informalexample>
- <para>This pattern continues for all other types of streams which can be received from a
- user. The instruction which begins the stream has a corresponding handler within
- <classname>guac_user</classname>, and the metadata describing that stream and
- provided with the instruction is included within the parameters passed to that
- handler.</para>
- <para>These handlers are, of course, optional. If any type of stream lacks a
- corresponding handler, guacd will automatically close the stream and respond with an
- <link xmlns:xlink="http://www.w3.org/1999/xlink" linkend="ack-instruction">"ack"
- instruction</link> and appropriate error code, informing the user's Guacamole
- client that the stream is unsupported.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/openid-auth.xml b/src/chapters/openid-auth.xml
deleted file mode 100644
index 646ea8f..0000000
--- a/src/chapters/openid-auth.xml
+++ /dev/null
@@ -1,211 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="openid-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>OpenID Connect Authentication</title>
- <indexterm>
- <primary>OpenID Connect Authentication</primary>
- </indexterm>
- <para><link xlink:href="http://openid.net/connect/">OpenID Connect</link> is a widely-adopted
- open standard for implementing single sign-on (SSO). <link
- xlink:href="https://oauth.net/articles/authentication/">Not to be confused with
- OAuth</link>, which is <emphasis>not</emphasis> an authentication protocol, OpenID
- Connect defines an authentication protocol in the form of a simple identity layer on top of
- OAuth 2.0.</para>
- <para>Guacamole's OpenID Connect support implements the "<link
- xlink:href="https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth"
- >implicit flow</link>" of the OpenID Connect standard, and allows authentication of
- Guacamole users to be delegated to an identity provider which implements OpenID Connect,
- removing the need for users to log into Guacamole directly. This module must be layered on
- top of other authentication extensions that provide connection information, such as the
- <link linkend="jdbc-auth">database authentication extension</link>, as it only provides
- user authentication.</para>
- <section xml:id="openid-downloading">
- <title>Downloading the OpenID Connect authentication extension</title>
- <para>The OpenID Connect authentication extension is available separately from the main
- <filename>guacamole.war</filename>. The link for this and all other
- officially-supported and compatible extensions for a particular version of Guacamole are
- provided on the release notes for that version. You can find the release notes for
- current versions of Guacamole here: <link
- xlink:href="http://guacamole.apache.org/releases/"
- >http://guacamole.apache.org/releases/</link>.</para>
- <para>The OpenID Connect authentication extension is packaged as a
- <filename>.tar.gz</filename> file containing only the extension itself,
- <filename>guacamole-auth-openid-1.3.0.jar</filename>, which must ultimately be
- placed in <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </section>
- <section xml:id="installing-openid-auth">
- <title>Installing support for OpenID Connect</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- located within the <filename>GUACAMOLE_HOME/extensions</filename> directory.
- <emphasis>If you are unsure where <varname>GUACAMOLE_HOME</varname> is located on
- your system, please consult <xref linkend="configuring-guacamole"/> before
- proceeding.</emphasis></para>
- <para>To install the OpenID Connect authentication extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Copy <filename>guacamole-auth-openid-1.3.0.jar</filename> within
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </step>
- <step>
- <para>Configure Guacamole to use OpenID Connect authentication, as described
- below.</para>
- </step>
- </procedure>
- <section xml:id="guac-openid-config">
- <title>Configuring Guacamole for single sign-on with OpenID Connect</title>
- <indexterm>
- <primary>configuring OpenID Connect authentication</primary>
- </indexterm>
- <indexterm>
- <primary>OpenID Connect authentication</primary>
- <secondary>configuration</secondary>
- </indexterm>
- <para>Guacamole's OpenID connect support requires several properties which describe both
- the identity provider and the Guacamole deployment. These properties are
- <emphasis>absolutely required in all cases</emphasis>, as they dictate how
- Guacamole should connect to the identity provider, how it should verify the identity
- provider's response, and how the identity provider should redirect users back to
- Guacamole once their identity has been confirmed:</para>
- <variablelist>
- <varlistentry>
- <term><property>openid-authorization-endpoint</property></term>
- <listitem>
- <para>The authorization endpoint (URI) of the OpenID service.</para>
- <para>This value should be provided to you by the identity provider. For
- identity providers that implement <link
- xlink:href="https://openid.net/specs/openid-connect-discovery-1_0.html"
- >OpenID Connect Discovery</link>, this value can be retrieved from
- the "<property>authorization_endpoint</property>" property of the JSON
- file hosted at
- <uri><replaceable>https://identity-provider</replaceable>/.well-known/openid-configuration</uri>,
- where <uri><replaceable>https://identity-provider</replaceable></uri> is
- the base URL of the identity provider.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>openid-jwks-endpoint</property></term>
- <listitem>
- <para>The endpoint (URI) of the JWKS service which defines how received ID
- tokens (<link xlink:href="https://jwt.io/">JSON Web Tokens</link> or
- JWTs) shall be validated.</para>
- <para>This value should be provided to you by the identity provider. For
- identity providers that implement <link
- xlink:href="https://openid.net/specs/openid-connect-discovery-1_0.html"
- >OpenID Connect Discovery</link>, this value can be retrieved from
- the "<property>jwks_uri</property>" property of the JSON file hosted at
- <uri><replaceable>https://identity-provider</replaceable>/.well-known/openid-configuration</uri>,
- where <uri><replaceable>https://identity-provider</replaceable></uri> is
- the base URL of the identity provider.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>openid-issuer</property></term>
- <listitem>
- <para>The issuer to expect for all received ID tokens.</para>
- <para>This value should be provided to you by the identity provider. For
- identity providers that implement <link
- xlink:href="https://openid.net/specs/openid-connect-discovery-1_0.html"
- >OpenID Connect Discovery</link>, this value can be retrieved from
- the "<property>issuer</property>" property of the JSON file hosted at
- <uri><replaceable>https://identity-provider</replaceable>/.well-known/openid-configuration</uri>,
- where <uri><replaceable>https://identity-provider</replaceable></uri> is
- the base URL of the identity provider.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>openid-client-id</property></term>
- <listitem>
- <para>The OpenID client ID which should be submitted to the OpenID service
- when necessary. This value is typically provided to you by the OpenID
- service when OpenID credentials are generated for your
- application.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>openid-redirect-uri</property></term>
- <listitem>
- <para>The URI that should be submitted to the OpenID service such that they
- can redirect the authenticated user back to Guacamole after the
- authentication process is complete. This must be the full URL that a
- user would enter into their browser to access Guacamole.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>Additional optional properties are available to control how claims within received
- ID tokens are used to derive the user's Guacamole username, any associated groups,
- the OpenID scopes requested when user identities are confirmed, and to control the
- maximum amount of time allowed for various aspects of the conversation with the
- identity provider:</para>
- <variablelist>
- <varlistentry>
- <term><property>openid-username-claim-type</property></term>
- <listitem>
- <para>The claim type within any valid JWT that contains the authenticated
- user's username. By default, the "<constant>email</constant>" claim type
- is used.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>openid-groups-claim-type</property></term>
- <listitem>
- <para>The claim type within any valid JWT that contains the list of groups
- of which the authenticated user is a member. By default, the
- "<constant>groups</constant>" claim type is used.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>openid-scope</property></term>
- <listitem>
- <para>The space-separated list of OpenID scopes to request. OpenID scopes
- determine the information returned within the OpenID token, and thus
- affect what values can be used as an authenticated user's username. To
- be compliant with OpenID, at least "<constant>openid profile</constant>"
- must be requested. By default, "<constant>openid email
- profile</constant>" is used.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>openid-allowed-clock-skew</property></term>
- <listitem>
- <para>The amount of clock skew tolerated for timestamp comparisons between
- the Guacamole server and OpenID service clocks, in seconds. By default,
- clock skew of up to 30 seconds is tolerated.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>openid-max-token-validity</property></term>
- <listitem>
- <para>The maximum amount of time that an OpenID token should remain valid,
- in minutes. By default, each OpenID token remains valid for 300 minutes
- (5 hours).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>openid-max-nonce-validity</property></term>
- <listitem>
- <para>The maximum amount of time that a nonce generated by the Guacamole
- server should remain valid, in minutes. As each OpenID request has a
- unique nonce value, this imposes an upper limit on the amount of time
- any particular OpenID request can result in successful authentication
- within Guacamole. By default, each generated nonce expires after 10
- minutes.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="completing-openid-install">
- <title>Completing the installation</title>
- <para>Guacamole will only reread <filename>guacamole.properties</filename> and load
- newly-installed extensions during startup, so your servlet container will need to be
- restarted before OpenID Connect authentication can be used. <emphasis>Doing this
- will disconnect all active users, so be sure that it is safe to do so prior to
- attempting installation.</emphasis> When ready, restart your servlet container
- and give the new authentication a try.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/protocol.xml b/src/chapters/protocol.xml
deleted file mode 100644
index 0ddb85c..0000000
--- a/src/chapters/protocol.xml
+++ /dev/null
@@ -1,443 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="guacamole-protocol" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>The Guacamole protocol</title>
- <indexterm>
- <primary>Guacamole protocol</primary>
- </indexterm>
- <para>This chapter is an overview of the Guacamole protocol, describing its design and general
- use. While a few instructions and their syntax will be described here, this is not an
- exhaustive list of all available instructions. The intent is only to list the general types
- and usage. If you are looking for the syntax or purpose of a specific instruction, consult
- the protocol reference included with the appendices.</para>
- <section xml:id="guacamole-protocol-design">
- <title>Design</title>
- <para>The Guacamole protocol consists of instructions. Each instruction is a comma-delimited
- list followed by a terminating semicolon, where the first element of the list is the
- instruction opcode, and all following elements are the arguments for that
- instruction:</para>
- <informalexample>
- <programlisting><replaceable>OPCODE</replaceable>,<replaceable>ARG1</replaceable>,<replaceable>ARG2</replaceable>,<replaceable>ARG3</replaceable>,<replaceable>...</replaceable>;</programlisting>
- </informalexample>
- <para>Each element of the list has a positive decimal integer length prefix separated by the
- value of the element by a period. This length denotes the number of Unicode characters
- in the value of the element, which is encoded in UTF-8:</para>
- <informalexample>
- <programlisting><replaceable>LENGTH</replaceable>.<replaceable>VALUE</replaceable></programlisting>
- </informalexample>
- <para>Any number of complete instructions make up a message which is sent from client to
- server or from server to client. Client to server instructions are generally control
- instructions (for connecting or disconnecting) and events (mouse and keyboard). Server
- to client instructions are generally drawing instructions (caching, clipping, drawing
- images), using the client as a remote display.</para>
- <para>For example, a complete and valid instruction for setting the display size to 1024x768
- would be:</para>
- <informalexample>
- <programlisting>4.size,1.0,4.1024,3.768;</programlisting>
- </informalexample>
- <para>Here, the instruction would be decoded into four elements: "size", the opcode of the
- size instruction, "0", the index of the default layer, "1024", the desired width in
- pixels, and "768", the desired height in pixels.</para>
- <para>The structure of the Guacamole protocol is important as it allows the protocol to be
- streamed while also being easily parsable by JavaScript. JavaScript does have native
- support for conceptually-similar structures like XML or JSON, but neither of those
- formats is natively supported in a way that can be streamed; JavaScript requires the
- entirety of the XML or JSON message to be available at the time of decoding. The
- Guacamole protocol, on the other hand, can be parsed as it is received, and the presence
- of length prefixes within each instruction element means that the parser can quickly
- skip around from instruction to instruction without having to iterate over every
- character.</para>
- </section>
- <section xml:id="guacamole-protocol-handshake">
- <title>Handshake phase</title>
- <para>The handshake phase is the phase of the protocol entered immediately upon connection.
- It begins with a "select" instruction sent by the client which tells the server which
- protocol will be loaded:</para>
- <informalexample>
- <programlisting>6.select,3.vnc;</programlisting>
- </informalexample>
- <para>After receiving the "select" instruction, the server will load the associated client
- support and respond with its protocol version and a list of accepted parameter names
- using an "args" instruction:</para>
- <informalexample>
- <programlisting>4.args,13.VERSION_1_1_0,8.hostname,4.port,8.password,13.swap-red-blue,9.read-only;</programlisting>
- </informalexample>
- <para>The protocol version is used to negotiate compatibility between differing
- versions of client and server, allowing the two sides to negotiate the highest
- supported version and enable or disable features associated with that version.
- Older versions of the Guacamole Client that do not support this instruction
- will silently ignore it as an empty connection parameter. Valid protocol versions
- are as follows:<informaltable frame="all">
- <tgroup cols="3">
- <colspec colname="c1" colnum="1" colwidth="1.25*"/>
- <colspec colname="c2" colnum="2" colwidth="3.25*"/>
- <colspec colname="c3" colnum="3" colwidth="9*"/>
- <thead>
- <row>
- <entry>Version</entry>
- <entry>Value</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>1.0.0</entry>
- <entry><constant>VERSION_1_0_0</constant></entry>
- <entry>This is the default version and applies to any
- versions prior to 1.1.0. Version 1.0.0 of the protocol
- does not support protocol negotiation, and requires that
- the handshake instructions are delivered in a certain
- order, and that they are present (even if empty).</entry>
- </row>
- <row>
- <entry>1.1.0</entry>
- <entry><constant>VERSION_1_1_0</constant></entry>
- <entry>Protocol version 1.1.0 introduces support for
- protocol version negotiation, arbitrary order of the
- handshake instructions, and support for passing the
- timezone instruction during the handshake.</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </para>
- <para>After receiving the list of arguments, the client is required to respond with the list
- of supported audio, video, and image mimetypes, the optimal display size and resolution,
- and the values for all arguments available, even if blank.</para>
- <informalexample>
- <programlisting>
-4.size,4.1024,3.768,2.96;
-5.audio,9.audio/ogg;
-5.video;
-5.image,9.image/png,10.image/jpeg;
-8.timezone,16.America/New_York;
-7.connect,13.VERSION_1_1_0,9.localhost,4.5900,0.,0.,0.;</programlisting>
- </informalexample>
- <para>For clarity, we've put each instruction on its own line, but in the real protocol, no
- newlines exist between instructions. In fact, if there is anything after an instruction
- other than the start of a new instruction, the connection is closed.</para>
- <para>The following are valid instructions during the handshake:</para>
- <informaltable frame="all">
- <indexterm>
- <primary>handshake</primary>
- <secondary>instructions</secondary>
- </indexterm>
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Instruction name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>audio</parameter></entry>
- <entry><para>The audio codec(s) supported by the client. In the example
- above the client is specifying audio/ogg as the supported codec.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>connect</parameter></entry>
- <entry><para>This is the final instruction of the handshake, terminating
- the handshake and indicating that the connection should continue.
- This instruction has as its parameters values for the connection
- parameters sent by the server in the <constant>args</constant>
- instruction. In the example above, this is connection to localhost
- on port 5900, with no values for the last three connection parameters.
- </para></entry>
- </row>
- <row>
- <entry><parameter>image</parameter></entry>
- <entry><para>The image formats that the client supports, in order of
- preference. The client in the example above is supporting both PNG
- and JPEG.</para></entry>
- </row>
- <row>
- <entry><parameter>timezone</parameter></entry>
- <entry><para>The timezone of the client, in IANA zone key format. More
- information on this instruction is available in
- <xref linkend="configuring-guacamole"/>, under documentation related
- to the <constant>timezone</constant> connection parameters for the
- protocols that support it.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>video</parameter></entry>
- <entry><para>The video codec(s) supported by the client. The above example
- is a client that does not support any video codecs.</para></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>The order of the instructions sent by the client in the handshake is arbitrary, with
- the exception that the final instruction, connect, will end the handshake and attempt
- to start the connection.</para>
- <para>Once these instructions have been sent by the client, the server will attempt to
- initialize the connection with the parameters received and, if successful, respond with
- a "ready" instruction. This instruction contains the ID of the new client connection and
- marks the beginning of the interactive phase. The ID is an arbitrary string, but is
- guaranteed to be unique from all other active connections, as well as from the names of
- all supported protocols:</para>
- <informalexample>
- <programlisting>5.ready,37.$260d01da-779b-4ee9-afc1-c16bae885cc7;</programlisting>
- </informalexample>
- <para>The actual interactive phase begins immediately after the "ready" instruction is sent.
- Drawing and event instructions pass back and forth until the connection is
- closed.</para>
- <section xml:id="guacamole-protocol-joining">
- <title>Joining an existing connection</title>
- <para>Once the handshake phase has completed, that connection is considered active and
- can be joined by other connections if the ID is provided instead of a protocol name
- via the "select" instruction:</para>
- <informalexample>
- <programlisting>6.select,37.$260d01da-779b-4ee9-afc1-c16bae885cc7;</programlisting>
- <para>The rest of the handshake phase for a joining connection is identical. Just as
- with a new connection, the restrictions or features which apply to the joining
- connection are dictated by the parameter values supplied during the
- handshake.</para>
- </informalexample>
- </section>
- </section>
- <section xml:id="guacamole-protocol-drawing">
- <title>Drawing</title>
- <section xml:id="guacamole-protocol-compositing">
- <title>Compositing</title>
- <para>The Guacamole protocol provides compositing operations through the use of "channel
- masks". The term "channel mask" is simply a description of the mechanism used while
- designing the protocol to conceptualize and fully enumerate all possible compositing
- operations based on four different sources of image data: source image data where
- the destination is opaque, source image data where the destination is transparent,
- destination image data where the source is opaque, and destination image data where
- the source is transparent. Assigning a binary value to each of these "channels"
- creates a unique integer ID for every possible compositing operation, where these
- operations parallel the operations described by Porter and Duff in their paper. As
- the HTML5 canvas tag also uses Porter/Duff to describe their compositing operations
- (as do other graphical APIs), the Guacamole protocol is conveniently similar to the
- compositing support already present in web browsers, with some operations not yet
- supported. The following operations are all implemented and known to work correctly
- in all browsers:</para>
- <variablelist>
- <varlistentry>
- <term>B out A (0x02)</term>
- <listitem>
- <para>Clears the destination where the source is opaque, but otherwise draws
- nothing. This is useful for masking.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>A atop B (0x06)</term>
- <listitem>
- <para>Fills with the source where the destination is opaque only.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>A xor B (0x0A)</term>
- <listitem>
- <para>As with logical XOR. Note that this is a compositing operation, not a
- bitwise operation. It draws the source where the destination is
- transparent, and draws the destination where the source is
- transparent.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>B over A (0x0B)</term>
- <listitem>
- <para>What you would typically expect when drawing, but reversed. The source
- appears only where the destination is transparent, as if you were
- attempting to draw the destination over the source, rather than the
- source over the destination.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>A over B (0x0E)</term>
- <listitem>
- <para>The most common and sensible compositing operation, this draws the
- source everywhere, but includes the destination where the source is
- transparent.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>A + B (0x0F)</term>
- <listitem>
- <para>Simply adds the components of the source image to the destination
- image, capping the result at pure white.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>The following operations are all implemented, but may work incorrectly in WebKit
- browsers which always include the destination image where the source is
- transparent:</para>
- <variablelist>
- <varlistentry>
- <term>B in A (0x01)</term>
- <listitem>
- <para>Draws the destination only where the source is opaque, clearing
- anywhere the source or destination are transparent.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>A in B (0x04)</term>
- <listitem>
- <para>Draws the source only where the destination is opaque, clearing
- anywhere the source or destination are transparent.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>A out B (0x08)</term>
- <listitem>
- <para>Draws the source only where the destination is transparent, clearing
- anywhere the source or destination are opaque.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>B atop A (0x09)</term>
- <listitem>
- <para>Fills with the destination where the source is opaque only.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>A (0x0C)</term>
- <listitem>
- <para>Fills with the source, ignoring the destination entirely.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>The following operations are defined, but not implemented, and do not exist as
- operations within the HTML5 canvas:</para>
- <variablelist>
- <varlistentry>
- <term>Clear (0x00)</term>
- <listitem>
- <para>Clears all existing image data in the destination.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>B (0x03)</term>
- <listitem>
- <para>Does nothing.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>A xnor B (0x05)</term>
- <listitem>
- <para>Adds the source to the destination where the destination or source are
- opaque, clearing anywhere the source or destination are transparent.
- This is similar to A + B except the aspect of transparency is also
- additive.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>(A + B) atop B (0x07)</term>
- <listitem>
- <para>Adds the source to the destination where the destination is opaque,
- preserving the destination otherwise.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>(A + B) atop A (0x0D)</term>
- <listitem>
- <para>Adds the destination to the source where the source is opaque, copying
- the source otherwise.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="guacamole-protocol-images">
- <title>Image data</title>
- <para>The Guacamole protocol, like many remote desktop protocols, provides a method of
- sending an arbitrary rectangle of image data and placing it either within a buffer
- or in a visible rectangle of the screen. Raw image data in the Guacamole protocol is
- streamed as PNG, JPEG, or WebP data over a stream allocated with the "img"
- instruction. Depending on the format used, image updates sent in this manner can be
- RGB or RGBA (alpha transparency) and are automatically palettized if sent using
- libguac. The streaming system used for image data is generalized and used by
- Guacamole for other types of streams, including audio and file transfer. For more
- information about streams in the Guacamole protocol, see <xref
- xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="guacamole-protocol-streaming"/>.</para>
- <para>Image data can be sent to any specified rectangle within a layer or buffer.
- Sending the data to a layer means that the image becomes immediately visible, while
- sending the data to a buffer allows that data to be reused later.</para>
- </section>
- <section xml:id="guacamole-protocol-copying-images">
- <title>Copying image data between layers</title>
- <para>Image data can be copied from one layer or buffer into another layer or buffer.
- This is often used for scrolling (where most of the result of the graphical update
- is identical to the previous state) or for caching parts of an image.</para>
- <para>Both VNC and RDP provide a means of copying a region of screen data and placing it
- somewhere else within the same screen. RDP provides an additional means of copying
- data to a cache, or recalling data from that cache and placing it on the screen.
- Guacamole takes this concept and reduces it further, as both on-screen and
- off-screen image storage is the same. The Guacamole "copy" instruction allows you to
- copy a rectangle of image data, and place it within another layer, whether that
- layer is the same as the source layer, a different visible layer, or an off-screen
- buffer.</para>
- </section>
- <section xml:id="guacamole-graphical-primitives">
- <title>Graphical primitives</title>
- <para>The Guacamole protocol provides basic graphics operations similar to those of
- Cairo or the HTML5 canvas. In many cases, these primitives are useful for remote
- drawing, and desirable in that they take up less bandwidth than sending
- corresponding PNG images. Beware that excessive use of primitives leads to an
- increase in client-side processing, which may reduce the performance of a connected
- client, especially if that client is on a lower-performance machine like a mobile
- phone or tablet.</para>
- </section>
- <section xml:id="guacamole-protocol-layers">
- <title>Buffers and layers</title>
- <para>All drawing operations in the Guacamole protocol affect a layer, and each layer
- has an integer index which identifies it. When this integer is negative, the layer
- is not visible, and can be used for storage or caching of image data. In this case,
- the layer is referred to within the code and within documentation as a "buffer".
- Layers are created automatically when they are first referenced in an
- instruction.</para>
- <para>There is one main layer which is always present called the "default layer". This
- layer has an index of 0. Resizing this layer resizes the entire remote display.
- Other layers default to the size of the default layer upon creation, while buffers
- are always created with a size of 0x0, automatically resizing themselves to fit
- their contents.</para>
- <para>Non-buffer layers can be moved and nested within each other. In this way, layers
- provide a simple means of hardware-accelerated compositing. If you need a window to
- appear above others, or you have some object which will be moving or you need the
- data beneath it automatically preserved, a layer is a good way of accomplishing
- this. If a layer is nested within another layer, its position is relative to that of
- its parent. When the parent is moved or reordered, the child moves with it. If the
- child extends beyond the parents bounds, it will be clipped.</para>
- </section>
- </section>
- <section xml:id="guacamole-protocol-streaming">
- <title>Streams and objects</title>
- <para>Guacamole supports transfer of clipboard contents, audio, video, and image data, as
- well as files and arbitrary named pipes.</para>
- <para>Streams are allocated directly with instructions that associate the new stream with
- particular semantics and metadata, such as the "audio" or "video" instructions used for
- playing media, the "file" instruction used for file transfer, and the "pipe" instruction
- for transfer of completely arbitrary data between client and server. In some cases, the
- availability and semantics of streams may be explicitly advertised using structured sets
- of named streams known as "objects".</para>
- <para>Once a stream is allocated, data is sent along the stream in chunks using "blob"
- instructions, which may be acknowledged by the receiving end by "ack" instructions. The
- end of the stream is finally signalled with an "end" instruction.</para>
- </section>
- <section xml:id="guacamole-protocol-events">
- <title>Events</title>
- <para>When something changes on either side, client or server, such as a key being pressed,
- the mouse moving, or clipboard data changing, an instruction describing the event is
- sent.</para>
- </section>
- <section xml:id="guacamole-protocol-disconnecting">
- <title>Disconnecting</title>
- <para>The server and client can end the connection at any time. There is no requirement for
- the server or the client to communicate that the connection needs to terminate. When the
- client or server wish to end the connection, and the reason is known, they can use the
- "disconnect" or "error" instructions.</para>
- <para>The disconnect instruction is sent by the client when it is disconnecting. This is
- largely out of politeness, and the server must be written knowing that the disconnect
- instruction may not always be sent in time (guacd is written this way).</para>
- <para>If the client does something wrong, or the server detects a problem with the client
- plugin, the server sends an error instruction, including a description of the problem in
- the parameters. This informs the client that the connection is being closed.</para>
- </section>
-</chapter>
diff --git a/src/chapters/radius-auth.xml b/src/chapters/radius-auth.xml
deleted file mode 100644
index 37b1c3d..0000000
--- a/src/chapters/radius-auth.xml
+++ /dev/null
@@ -1,255 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="radius-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>RADIUS Authentication</title>
- <indexterm>
- <primary>RADIUS Authentication</primary>
- </indexterm>
- <para>Guacamole supports delegating authentication to a RADIUS service, such as FreeRADIUS, to
- validate username and password combinations, and to support multi-factor authentication. This
- authentication method must be layered on top of some other authentication extension, such as
- those available from the main project website, in order to provide access to actual
- connections.</para>
- <section xml:id="radius-downloading">
- <title>Downloading the RADIUS authentication extension</title>
- <para>The RADIUS extension depends on software that is covered by a LGPL license, which is
- incompatible with the Apache 2.0 license under which Guacamole is licensed. Due to this
- dependency, the Guacamole project cannot distribute binary versions of the RADIUS extension.
- If you want to use this extension you will need to build the code - or at least the RADIUS
- extension yourself. Build instructions can be found in the section
- <xref linkend="installing-guacamole"/>.</para>
- </section>
- <section xml:id="installing-radius-auth">
- <title>Installing RADIUS authentication</title>
- <para>The RADIUS extension must be explicitly enabled during build time in order to generate
- the binaries and resulting JAR file. This is done by adding the flag <option>-Plgpl-extensions</option>
- to the Maven command line during the build, and should result in the output below:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>mvn clean package -Plgpl-extensions</userinput>
-<computeroutput>[INFO] --- maven-assembly-plugin:2.5.3:single (make-source-archive) @ guacamole-client ---
-[INFO] Reading assembly descriptor: project-assembly.xml
-[INFO] Building tar: /home/guac/guacamole-client/target/guacamole-client-1.3.0.tar.gz
-[INFO] ------------------------------------------------------------------------
-[INFO] Reactor Summary:
-[INFO]
-[INFO] guacamole-common .................................. SUCCESS [6.037s]
-[INFO] guacamole-ext ..................................... SUCCESS [5.382s]
-[INFO] guacamole-common-js ............................... SUCCESS [0.751s]
-[INFO] guacamole ......................................... SUCCESS [9.767s]
-[INFO] guacamole-auth-cas ................................ SUCCESS [2.811s]
-[INFO] guacamole-auth-duo ................................ SUCCESS [2.441s]
-[INFO] guacamole-auth-header ............................. SUCCESS [1.875s]
-[INFO] guacamole-auth-jdbc ............................... SUCCESS [0.277s]
-[INFO] guacamole-auth-jdbc-base .......................... SUCCESS [2.144s]
-[INFO] guacamole-auth-jdbc-mysql ......................... SUCCESS [5.637s]
-[INFO] guacamole-auth-jdbc-postgresql .................... SUCCESS [5.465s]
-[INFO] guacamole-auth-jdbc-sqlserver ..................... SUCCESS [5.398s]
-[INFO] guacamole-auth-jdbc-dist .......................... SUCCESS [0.824s]
-[INFO] guacamole-auth-ldap ............................... SUCCESS [2.743s]
-[INFO] guacamole-auth-noauth ............................. SUCCESS [0.964s]
-[INFO] guacamole-auth-openid ............................. SUCCESS [2.533s]
-[INFO] guacamole-example ................................. SUCCESS [0.888s]
-[INFO] guacamole-playback-example ........................ SUCCESS [0.628s]
-[INFO] guacamole-auth-radius ............................. SUCCESS [17.729s]
-[INFO] guacamole-client .................................. SUCCESS [5.645s]
-[INFO] ------------------------------------------------------------------------
-[INFO] BUILD SUCCESS
-[INFO] ------------------------------------------------------------------------
-[INFO] Total time: 1:20.134s
-[INFO] Finished at: Wed Jan 31 09:45:41 EST 2018
-[INFO] Final Memory: 47M/749M
-[INFO] ------------------------------------------------------------------------</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
-
- <para>After the build completes successfully, the extension will be in the
- <filename>extensions/guacamole-auth-radius/target/</filename> directory, and will be
- called guacamole-auth-radius-1.3.0.jar. This extension file can be copied to
- the <filename>GUACAMOLE_HOME/extensions</filename> directory.
- <emphasis>If you are unsure where <varname>GUACAMOLE_HOME</varname> is located on
- your system, please consult <xref linkend="configuring-guacamole"/> before
- proceeding.</emphasis></para>
-
- <para>Extensions are loaded in alphabetical order, and authentication is performed
- in the order in which the extensions were loaded. If you are stacking the
- RADIUS extension with another extension, like the JDBC extension, in order to
- store connection information, you may need to change the name of the RADIUS
- extension such that it is evaluated prior to the JDBC extension - otherwise
- an authentication failure in one of the previous modules may block the RADIUS
- module from ever being evaluated.</para>
-
- <para>To install the RADIUS authentication extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Copy <filename>guacamole-auth-radius-1.3.0.jar</filename> into
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </step>
- <step>
- <para>Configure Guacamole to use RADIUS authentication, as described
- below.</para>
- </step>
- </procedure>
- </section>
- <section xml:id="guac-radius-config">
- <title>Configuring Guacamole for RADIUS authentication</title>
- <indexterm>
- <primary>configuring RADIUS authentication</primary>
- </indexterm>
- <indexterm>
- <primary>RADIUS authentication</primary>
- <secondary>configuration</secondary>
- </indexterm>
- <para>This extension provides several configuration properties in order
- to communicate properly with the RADIUS server to which it needs to authenticate. It is
- important that you know several key pieces of information about the RADIUS server -
- at a minimum, the server name or IP, the authentication port, the authentication
- protocol in use by the server, and the shared secret for the RADIUS client. If you
- are responsible for the RADIUS server, you'll need to properly configure these items
- to get Guacamole to authenticate properly. If you're not responsible for the RADIUS
- server you will need to work with the administrator to get all of the necessary
- configuration items for the server. These items will need to be configured in the
- <link linkend="initial-setup"><filename>guacamole.properties</filename></link>
- file.</para>
- <variablelist>
- <varlistentry>
- <term><property>radius-hostname</property></term>
- <listitem>
- <para>The RADIUS server to authenticate against. If not specified,
- localhost will be used.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-auth-port</property></term>
- <listitem>
- <para>The RADIUS authentication port on which the RADIUS service is
- is listening. If not specified, the default of 1812 will be
- used.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-shared-secret</property></term>
- <listitem>
- <para>The shared secret to use when talking to the RADIUS server. This
- parameter is required and the extension will not load if this is not
- specified.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-auth-protocol</property></term>
- <listitem>
- <para>The authentication protocol to use when talking to the RADIUS server.
- This parameter is required for the extension to operate. Supported
- values are: pap, chap, mschapv1, mschapv2, eap-md5, eap-tls, and eap-ttls.
- Support for PEAP is implemented inside the extension, but, due to a regression
- in the JRadius implementation, it is currently broken. Also, if you specify
- eap-ttls you will also need to specify the
- <property>radius-eap-ttls-inner-protocol</property> parameter in order to
- properly configure the protocol used inside the EAP TTLS tunnel.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-key-file</property></term>
- <listitem>
- <para>The combination certificate and private key pair to use for TLS-based
- RADIUS protocols that require a client-side certificate. This parameter
- should specify the absolute path to the file. By default the extension
- will look for a file called radius.key in the GUACAMOLE_HOME directory.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-key-type</property></term>
- <listitem>
- <para>The file type of the keystore specified by the <property>radius-key-file</property>
- parameter. Valid keystore types are pem, jceks, jks, and pkcs12.
- If not specified, this defaults to pkcs12, the default used by
- the JRadius library.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-key-password</property></term>
- <listitem>
- <para>The password of the private key specified in the
- <property>radius-key-file</property> parameter. By default the extension
- will not use any password when trying to open the key file.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-ca-file</property></term>
- <listitem>
- <para>The absolute path to the file that stores the certificate authority
- certificates for encrypted connections to the RADIUS server. By default
- a file with the name ca.crt in the GUACAMOLE_HOME directory will be used.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-ca-type</property></term>
- <listitem>
- <para>The file type of keystore used for the certificate authority. Valid formats are
- pem, jceks, jks, and pkcs12. If not specified this defaults to pem.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-ca-password</property></term>
- <listitem>
- <para>The password used to protect the certificate authority store, if
- any. If unspecified the extension will attempt to read the CA
- store without any password.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-trust-all</property></term>
- <listitem>
- <para>This parameter controls whether or not the RADIUS extension
- should trust all certificates or verify them against known good
- certificate authorities. Set to true to allow the RADIUS server
- to connect without validating certificates. The default is false,
- which causes certificates to be validated.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-retries</property></term>
- <listitem>
- <para>The number of times the client will retry the connection to the
- RADIUS server and not receive a response before giving up. By default
- the client will try the connection at most 5 times.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-timeout</property></term>
- <listitem>
- <para>The timeout for a RADIUS connection in seconds. By default the client
- will wait for a response from the server for at most 60 seconds.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>radius-eap-ttls-inner-protocol</property></term>
- <listitem>
- <para>When EAP-TTLS is used, this parameter specifies the inner (tunneled)
- protocol to use talking to the RADIUS server. It is required when the
- <property>radius-auth-protocol</property> parameter is set to eap-ttls.
- If the <property>radius-auth-protocol</property> value is set to something
- other than eap-ttls, this parameter has no effect and will be ignored. Valid
- options for this are any of the values for
- <property>radius-auth-protocol</property>, except for eap-ttls.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="completing-radius-install">
- <title>Completing the installation</title>
- <para>Guacamole will only reread <filename>guacamole.properties</filename> and load
- newly-installed extensions during startup, so your servlet container will need to be
- restarted before HTTP header authentication can be used. <emphasis>Doing this will
- disconnect all active users, so be sure that it is safe to do so prior to
- attempting installation.</emphasis> When ready, restart your servlet container
- and give the new authentication a try.</para>
- </section>
-</chapter>
diff --git a/src/chapters/reverse-proxy.xml b/src/chapters/reverse-proxy.xml
deleted file mode 100644
index 0e9106c..0000000
--- a/src/chapters/reverse-proxy.xml
+++ /dev/null
@@ -1,369 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="proxying-guacamole" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Proxying Guacamole</title>
- <para>Like most web applications, Guacamole can be placed behind a reverse proxy. For production
- deployments of Guacamole, this is <emphasis>highly recommended</emphasis>. It provides
- flexibility and, if your proxy is properly configured for SSL, encryption.</para>
- <para>Proxying isolates privileged operations within native applications that can safely drop
- those privileges when no longer needed, using Java only for unprivileged tasks. On Linux and
- UNIX systems, a process must be running with root privileges to listen on any port under
- 1024, including the standard HTTP and HTTPS ports (80 and 443 respectively). If the servlet
- container instead listens on a higher port, such as the default port 8080, it can run as a
- reduced-privilege user, allowing the reverse proxy to bear the burden of root privileges. As
- a native application, the reverse proxy can make system calls to safely drop root privileges
- once the port is open; a Java application like Tomcat cannot do this.</para>
- <section xml:id="preparing-servlet-container">
- <title>Preparing your servlet container</title>
- <para>Your servlet container is most likely already configured to listen for HTTP
- connections on port 8080 as this is the default. If this is the case, and you can
- already access Guacamole over port 8080 from a web browser, you need not make any
- further changes to its configuration.</para>
- <para>If you <emphasis>have</emphasis> changed this, perhaps with the intent of proxying
- Guacamole over AJP, <emphasis>change it back</emphasis>. Using Guacamole over AJP is
- unsupported as it is known to cause problems, namely:</para>
- <orderedlist>
- <listitem>
- <para>WebSocket will not work over AJP, forcing Guacamole to fallback to HTTP,
- possibly resulting in reduced performance.</para>
- </listitem>
- <listitem>
- <para>Apache 2.4.3 and older does not support the HTTP PATCH method over AJP,
- preventing the Guacamole management interface from functioning properly.</para>
- </listitem>
- </orderedlist>
- <para>The connector entry within <filename>conf/server.xml</filename> should look like
- this:</para>
- <informalexample>
- <programlisting><Connector port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000"
- URIEncoding="UTF-8"
- redirectPort="8443" /></programlisting>
- </informalexample>
- <para>Be sure to specify the <code>URIEncoding="UTF-8"</code> attribute as above to ensure
- that connection names, user names, etc. are properly received by the web application. If
- you will be creating connections that have Cyrillic, Chinese, Japanese, or other
- non-Latin characters in their names or parameter values, this attribute is
- required.</para>
- <section xml:id="tomcat-remote-ip">
- <title>Setting up the Remote IP Valve</title>
- <para>By default, when Tomcat is behind a reverse proxy, the remote IP address of the
- client that it sees is that of the proxy rather than the original client. In order
- to allow applications hosted within Tomcat, like Guacamole, to see the actual IP
- address of the client, you have to configure both the reverse proxy and Tomcat.</para>
- <para>Because the remote IP address in Guacamole is used for auditing of user logins and
- connections and could potentially be used for authentication, it is important that you
- are either in direct control of the proxy server or you explicitly trust it. Passing
- the remote IP address is done using the <code>X-Forwarded-For</code> header, and,
- as with most HTTP headers, attackers can attempt to spoof this header in order to
- manipulate the behavior of the web server, gain unauthorized access to the system,
- or attempt to disguise the host or IP address they are coming from.</para>
- <para>One final caveat: This may not work as expected if there are other upstream proxy
- servers between your reverse proxy and the clients access Guacamole. Other proxies
- or firewalls can mask the IP address of the client, and if the configuration of
- those is not within your control you may end up with multiple clients appearing to
- come from the same IP address or host. Make sure you take this into account when
- configuring the system and looking at the data provided.</para>
- <para>Configuring Tomcat to pass through the remote IP address provided by the reverse
- proxy in the <code>X-Forwarded-For</code> header requires the configuration of what
- Tomcat calls a Valve. In this case, it is the <link
- xl:href="https://tomcat.apache.org/tomcat-8.5-doc/config/valve.html#Remote_IP_Valve">
- <code>RemoteIpValve</code></link> and is configured in the
- <filename>conf/server.xml</filename> file, in the <code><Host></code> section:
- </para>
- <informalexample>
- <programlisting><Valve className="org.apache.catalina.valves.RemoteIpValve"
- internalProxies="127.0.0.1"
- remoteIpHeader="x-forwarded-for"
- remoteIpProxiesHeader="x-forwarded-by"
- protocolHeader="x-forwarded-proto" /></programlisting>
- </informalexample>
- <para>The <parameter>internalProxies</parameter> value should be set to the IP address
- or addresses of any and all reverse proxy servers that will be accessing this Tomcat
- instance directly. Often it is run on the same system that runs Tomcat, but in other
- cases (for example, when running Docker), it may be on a different system/container and
- may need to be set to the actual IP address of the reverse proxy system. Only proxy
- servers listed in the <parameter>internalProxies</parameter> or
- <parameter>trustedProxies</parameter> parameters will be allowed to manipulate the
- remote IP address information. The other parameters in this configuration line allow
- you to control which headers coming from the proxy server(s) are used for various
- remote host information. They are as follows:
- </para>
- <informaltable frame="all">
- <tgroup cols="2">
- <colspec colname="c1" colnum="1" colwidth="1*"/>
- <colspec colname="c2" colnum="2" colwidth="3.55*"/>
- <thead>
- <row>
- <entry>Parameter name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><parameter>remoteIpHeader</parameter></entry>
- <entry>
- <para>The header that is queried to learn the client IP address
- of the client that originated the request. The standard
- value is <code>X-Forwarded-For</code>, but can
- be configured to any header you like. The IP address in this
- header will be available to Java applications in the
- <code>request.getRemoteAddr()</code> method.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>remoteIpProxiesHeader</parameter></entry>
- <entry>
- <para>The header that is queried to learn the IP address of the
- proxy server that forwarded the request. The default value
- is <code>X-Forwarded-By</code>, but can be configured to
- any header that fits your environment. This value will only
- be allowed by the valve if the proxy used is listed in the
- <parameter>trustedProxies</parameter> parameter. Otherwise
- this header will not be available.</para>
- </entry>
- </row>
- <row>
- <entry><parameter>protocolHeader</parameter></entry>
- <entry>
- <para>The header that is queried to determine the protocol
- that the client used to connect to the service. The default
- value is <code>X-Forwarded-Proto</code>, but can be
- configured to fit your environment.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>In addition to configuring Tomcat to properly handle these headers, you also may
- need to configure your reverse proxy appropriately to send the headers. You can
- find instructions for this in <xref linkend="nginx"/> - the Apache web server
- passes it through by default.</para>
- </section>
- </section>
- <section xml:id="nginx">
- <title>Nginx</title>
- <para>Nginx can be used as a reverse proxy, and supports WebSocket out-of-the-box <link
- xl:href="http://nginx.com/blog/websocket-nginx/">since version 1.3</link>. Both
- Apache and Nginx require some additional configuration for proxying of WebSocket to work
- properly.</para>
- <section xml:id="proxying-with-nginx">
- <title>Proxying Guacamole</title>
- <para>Nginx does support WebSocket for proxying, but requires that the "Connection" and
- "Upgrade" HTTP headers are set explicitly due to the nature of the WebSocket
- protocol. From the Nginx documentation:</para>
- <blockquote>
- <para>NGINX supports WebSocket by allowing a tunnel to be set up between a client
- and a back-end server. For NGINX to send the Upgrade request from the client to
- the back-end server, Upgrade and Connection headers must be set explicitly.
- ...</para>
- </blockquote>
- <para>The proxy configuration belongs within a dedicated <link
- xl:href="http://nginx.org/en/docs/http/ngx_http_core_module.html#location"
- ><code>location</code></link> block, declaring the backend hosting Guacamole
- and explicitly specifying the "Connection" and "Upgrade" headers mentioned
- earlier:</para>
- <informalexample>
- <programlisting>location /guacamole/ {
- proxy_pass http://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/;
- proxy_buffering off;
- proxy_http_version 1.1;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection $http_connection;
- access_log off;
-}</programlisting>
- </informalexample>
- <para>Here, <replaceable>HOSTNAME</replaceable> is the hostname or IP address of the
- machine hosting your servlet container, and <replaceable>8080</replaceable> is the
- port that servlet container is configured to use. You will need to replace these
- values with the correct values for your server.</para>
- <para>Related to the RemoteIpValve configuration for tomcat, documented in
- <xref linkend="tomcat-remote-ip"/>, the
- <code>proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</code> line is
- important if you want the <code>X-Forwarded-For</code> header to be passed through
- to the web application server and available to applications running inside it.</para>
- <important>
- <para><emphasis>Do not forget to specify "<code>proxy_buffering
- off</code>".</emphasis></para>
- <para>Most proxies, including Nginx, will buffer all data sent over the connection,
- waiting until the connection is closed before sending that data to the client.
- As Guacamole's HTTP tunnel relies on streaming data to the client over an open
- connection, excessive buffering will effectively block Guacamole connections,
- rendering Guacamole useless.</para>
- <para><emphasis>If the option "<code>proxy_buffering off</code>" is not specified,
- Guacamole may not work</emphasis>.</para>
- </important>
- </section>
- <section xml:id="changing-path-with-nginx">
- <title>Changing the path</title>
- <para>If you wish to serve Guacamole through Nginx under a path other than
- <uri>/guacamole/</uri>, the configuration will need to be altered slightly to
- take cookies into account. Although Guacamole does not rely on receipt of cookies in
- general, cookies are required for the proper operation of the HTTP tunnel. If the
- HTTP tunnel is used, and cookies cannot be set, users may be unexpectedly denied
- access to their connections.</para>
- <para>Regardless of the location specified for the proxy, cookies set by Guacamole will
- be set using its own absolute path within the backend (<uri>/guacamole/</uri>). If
- this path differs from that used by Nginx, the path in the cookie needs to be
- modified using <code>proxy_cookie_path</code>:</para>
- <informalexample>
- <programlisting>location /<replaceable>new-path/</replaceable> {
- proxy_pass http://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/;
- proxy_buffering off;
- proxy_http_version 1.1;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection $http_connection;
- <emphasis>proxy_cookie_path /guacamole/ /<replaceable>new-path/</replaceable>;</emphasis>
- access_log off;
-}</programlisting>
- </informalexample>
- </section>
- <section xml:id="nginx-file-upload-size">
- <title>Adjusting file upload limits</title>
- <para>When proxying Guacamole through Nginx, you may run into issues with the default
- limitations that Nginx places on file uploads (1MB). The errors you receive can
- be non-intuitive (permission denied, for example), but may be indicative of these
- limits. The <code>client_max_body_size</code> parameter can be set within the
- <code>location</code> block to configure the maximum file upload size:</para>
- <informalexample>
- <programlisting>location /guacamole/ {
- proxy_pass http://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/;
- proxy_buffering off;
- proxy_http_version 1.1;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection $http_connection;
- <emphasis>client_max_body_size <replaceable>1g</replaceable>;</emphasis>
- access_log off;
-}</programlisting>
- </informalexample>
- </section>
- </section>
- <section xml:id="apache">
- <title>Apache and <package>mod_proxy</package></title>
- <para>Apache supports reverse proxy configurations through <link
- xl:href="http://httpd.apache.org/docs/2.4/mod/mod_proxy.html"
- ><package>mod_proxy</package></link>. Apache 2.4.5 and later also support
- proxying of WebSocket through a sub-module called <link
- xl:href="http://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html"
- ><package>mod_proxy_wstunnel</package></link>. Both of these modules will need
- to be enabled for proxying of Guacamole to work properly.</para>
- <para>Lacking <package>mod_proxy_wstunnel</package>, it is still possible to proxy
- Guacamole, but Guacamole will be unable to use WebSocket. It will instead fallback to
- using the HTTP tunnel, resulting in reduced performance.</para>
- <section xml:id="proxying-with-apache">
- <title>Proxying Guacamole</title>
- <para>Configuring Apache to proxy HTTP requests requires using the
- <parameter>ProxyPass</parameter> and <parameter>ProxyPassReverse</parameter>
- directives, which are provided by the <package>mod_proxy</package> module. These
- directives describe how HTTP traffic should be routed to the web server behind the
- proxy:</para>
- <informalexample>
- <programlisting><Location /guacamole/>
- Order allow,deny
- Allow from all
- ProxyPass http://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/ flushpackets=on
- ProxyPassReverse http://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/
-</Location></programlisting>
- </informalexample>
- <para>Here, <replaceable>HOSTNAME</replaceable> is the hostname or IP address of the
- machine hosting your servlet container, and <replaceable>8080</replaceable> is the
- port that servlet container is configured to use. You will need to replace these
- values with the correct values for your server.</para>
- <important>
- <para><emphasis>Do not forget the <option>flushpackets=on</option>
- option.</emphasis></para>
- <para>Most proxies, including <package>mod_proxy</package>, will buffer all data
- sent over the connection, waiting until the connection is closed before sending
- that data to the client. As Guacamole's HTTP tunnel relies on streaming data to
- the client over an open connection, excessive buffering will effectively block
- Guacamole connections, rendering Guacamole useless.</para>
- <para><emphasis>If the option <option>flushpackets=on</option> is not specified,
- Guacamole may not work</emphasis>.</para>
- </important>
- </section>
- <section xml:id="websocket-and-apache">
- <title>Proxying the WebSocket tunnel</title>
- <para>Apache will not automatically proxy WebSocket connections, but you can proxy them
- separately with Apache 2.4.5 and later using <package>mod_proxy_wstunnel</package>.
- After enabling <package>mod_proxy_wstunnel</package> a secondary
- <code>Location</code> section can be added which explicitly proxies the
- Guacamole WebSocket tunnel, located at
- <uri>/guacamole/websocket-tunnel</uri>:</para>
- <informalexample>
- <programlisting><Location /guacamole/websocket-tunnel>
- Order allow,deny
- Allow from all
- ProxyPass ws://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/websocket-tunnel
- ProxyPassReverse ws://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/websocket-tunnel
-</Location></programlisting>
- </informalexample>
- <para>Lacking this, Guacamole will still work by using normal HTTP, but network latency
- will be more pronounced with respect to user input, and performance may be
- lower.</para>
- <important>
- <para>The <code>Location</code> section for <uri>/guacamole/websocket-tunnel</uri>
- must be placed after the <code>Location</code> section for the rest of
- Guacamole.</para>
- <para>Apache evaluates all Location sections, giving priority to the last section
- that matches. If the <uri>/guacamole/websocket-tunnel</uri> section comes first,
- the section for <uri>/guacamole/</uri> will match instead, and WebSocket will
- not be proxied correctly.</para>
- </important>
- </section>
- <section xml:id="changing-path-with-apache">
- <title>Changing the path</title>
- <para>If you wish to serve Guacamole through Apache under a path other than
- <uri>/guacamole/</uri>, the configuration required for Apache will be slightly
- different than the examples above due to cookies.</para>
- <para>Guacamole does not rely on receipt of cookies for tracking whether a user is
- logged in, but cookies are required for the proper operation of the HTTP tunnel. If
- the HTTP tunnel is used, and cookies cannot be set, users will be unexpectedly
- denied access to connections they legitimately should have access to.</para>
- <para>Cookies are set using the absolute path of the web application
- (<uri>/guacamole/</uri>). If this path differs from that used by Apache, the
- path in the cookie needs to be modified using the
- <parameter>ProxyPassReverseCookiePath</parameter> directive:</para>
- <informalexample>
- <programlisting><Location /<replaceable>new-path/</replaceable>>
- Order allow,deny
- Allow from all
- ProxyPass http://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/ flushpackets=on
- ProxyPassReverse http://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/
- <emphasis>ProxyPassReverseCookiePath /guacamole/ /<replaceable>new-path/</replaceable></emphasis>
-</Location>
-
-<Location /<replaceable>new-path</replaceable>/websocket-tunnel>
- Order allow,deny
- Allow from all
- ProxyPass ws://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/websocket-tunnel
- ProxyPassReverse ws://<replaceable>HOSTNAME</replaceable>:<replaceable>8080</replaceable>/guacamole/websocket-tunnel
-</Location></programlisting>
- </informalexample>
- <para>This directive is not needed for the WebSocket section, as it is not applicable.
- Cookies are only used by Guacamole within the HTTP tunnel.</para>
- </section>
- <section xml:id="disable-tunnel-logging">
- <title>Disabling logging of tunnel requests</title>
- <para>If WebSocket is unavailable, Guacamole will fallback to using an HTTP-based
- tunnel. The Guacamole HTTP tunnel works by transferring a continuous stream of data
- over multiple short-lived streams, each associated with a separate HTTP request. By
- default, Apache will log each of these requests, resulting in a rather bloated
- access log.</para>
- <para>There is little value in a log file filled with identical tunnel requests, so it
- is recommended to explicitly disable logging of those requests. Apache does provide
- a means of matching URL patterns and setting environment variables based on whether
- the URL matches. Logging can then be restricted to requests which lack this
- environment variable:</para>
- <informalexample>
- <programlisting>SetEnvIf Request_URI "^<replaceable>/guacamole</replaceable>/tunnel" dontlog
-CustomLog <replaceable>/var/log/apache2/guac.log</replaceable> common env=!dontlog</programlisting>
- </informalexample>
- <para>Note that if you are serving Guacamole under a path different from
- <uri>/guacamole/</uri>, you will need to change the value of
- <parameter>Request_URI</parameter> above accordingly.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/saml-auth.xml b/src/chapters/saml-auth.xml
deleted file mode 100644
index 833e1e2..0000000
--- a/src/chapters/saml-auth.xml
+++ /dev/null
@@ -1,179 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="saml-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>SAML Authentication</title>
- <indexterm>
- <primary>SAML Authentication</primary>
- </indexterm>
- <para>SAML is a widely implemented and used Single Sign On (SSO) provider that allows
- applications and services to authenticate in a standard way, and brokers those
- authentication requests to one or more back-end authentication providers. The SAML
- authentication extension allows Guacamole to redirect to a SAML Identity Provider (IdP)
- for authentication and user services. This module does not provide any capability
- for storing or retrieving connections, and must be layered with other authentication
- extensions that provide connection management.</para>
- <section xml:id="saml-downloading">
- <title>Downloading the SAML authentication extension</title>
- <para>The SAML authentication extension is available separately from the main
- <filename>guacamole.war</filename>. The link for this and all other
- officially-supported and compatible extensions for a particular version of Guacamole are
- provided on the release notes for that version. You can find the release notes for
- current versions of Guacamole here: <link
- xlink:href="http://guacamole.apache.org/releases/"
- >http://guacamole.apache.org/releases/</link>.</para>
- <para>The SAML authentication extension is packaged as a <filename>.tar.gz</filename>
- file containing only the extension itself,
- <filename>guacamole-auth-saml-1.3.0.jar</filename>, which must
- ultimately be placed in <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </section>
- <section xml:id="installing-saml-auth">
- <title>Installing SAML authentication</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- located within the <filename>GUACAMOLE_HOME/extensions</filename> directory.
- <emphasis>If you are unsure where <varname>GUACAMOLE_HOME</varname> is located on
- your system, please consult <xref linkend="configuring-guacamole"/> before
- proceeding.</emphasis></para>
- <para>To install the SAML authentication extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Copy <filename>guacamole-auth-saml-1.3.0.jar</filename> within
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </step>
- <step>
- <para>Configure Guacamole to use SAML authentication, as described
- below.</para>
- </step>
- </procedure>
- <section xml:id="guac-saml-config">
- <title>Configuring Guacamole for SAML Authentication</title>
- <indexterm>
- <primary>configuring SAML authentication</primary>
- </indexterm>
- <indexterm>
- <primary>SAML authentication</primary>
- <secondary>configuration</secondary>
- </indexterm>
- <para>The SAML authentication extension provides several configuration properties
- to set it up to talk to the IdP. The SAML IdP also must be configured with
- Guacamole as a Service Provider (SP). Configuration of the SAML IdP is beyond
- the scope of this document, and will vary widely based on the IdP in use.</para>
- <variablelist>
- <varlistentry>
- <term><property>saml-idp-metadata-url</property></term>
- <listitem>
- <para>The URI of the XML metadata file that from the
- SAML Identity Provider that contains all of the
- information the SAML extension needs in order to
- know how to authenticate with the IdP. This URI can
- either be a remote server (e.g. https://) or a local
- file on the filesystem (e.g. file://). Often the
- metadata file contains most of the required
- properties for SAML authentication and the other
- parameters are not required.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>saml-idp-url</property></term>
- <listitem>
- <para>The base URL of the SAML IdP. This is the URL that
- the SAML authentication extension will use to redirect
- when requesting SAML authentication. If the
- <property>saml-idp-metadata</property> property is
- provided, this parameter will be ignored. If the metadata
- file is not provided this property is required.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>saml-entity-id</property></term>
- <listitem>
- <para>The entity ID of the Guacamole SAML client, which is
- generally the URL of the Guacamole server, but is not
- required to be so. This property is required if
- either the <property>saml-idp-metadata-url</property>
- property is not specified, or if the provided
- metadata file does not contain the SAML SP Entity
- ID for Guacamole Client.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>saml-callback-url</property></term>
- <listitem>
- <para>The URL that the IdP will use once authentication has
- succeeded to return to the Guacamole web application and
- provide the authentication details to the SAML extension.
- The SAML extension currently only supports callback as a
- POST operation to this callback URL. This property
- is required.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>saml-strict</property></term>
- <listitem>
- <para>Require strict security checks during SAML logins.
- This will insure that valid certificates are
- present for all interactions with SAML servers and
- fail SAML authentication if security restrictions
- are violated. This property is optional, and will
- default to true, requiring strict security checks.
- This property should only be set to false in
- non-production environments during testing of
- SAML authentication.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>saml-debug</property></term>
- <listitem>
- <para>Enable additional logging within the supporting
- SAML library that can assist in tracking down issues
- during SAML logins. This property is optional, and
- will default to false (no debugging).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>saml-compress-request</property></term>
- <listitem>
- <para>Enable compression of the HTTP requests sent to
- the SAML IdP. This property is optional and will
- default to true (compression enabled).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>saml-compress-response</property></term>
- <listitem>
- <para>Request that the SAML response returned by the
- IdP be compressed. This property is optional and
- will default to true (compression will be requested).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>saml-group-attribute</property></term>
- <listitem>
- <para>The name of the attribute provided by the SAML IdP
- that contains group membership of the user. These
- groups will be parsed and used to map group
- membership of the user logging in, which can be used
- for permissions management within Guacamole Client,
- particularly when layered with other authentication
- modules. This property is optional, and defaults to
- "groups".</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="completing-saml-install">
- <title>Completing the installation</title>
- <para>Guacamole will only reread <filename>guacamole.properties</filename> and load
- newly-installed extensions during startup, so your servlet container will need to be
- restarted before SAML authentication can be used. <emphasis>Doing this will
- disconnect all active users, so be sure that it is safe to do so prior to
- attempting installation.</emphasis> When ready, restart your servlet container
- and give the new authentication a try.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/totp-auth.xml b/src/chapters/totp-auth.xml
deleted file mode 100644
index 32954a3..0000000
--- a/src/chapters/totp-auth.xml
+++ /dev/null
@@ -1,197 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="totp-auth" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>TOTP two-factor authentication</title>
- <indexterm>
- <primary>TOTP</primary>
- </indexterm>
- <para>Guacamole supports TOTP as a second authentication factor, layered on top of any other
- authentication extension, including those available from the main project website, providing
- <link linkend="totp-prerequisites">base requirements for key storage and
- enrollment</link> are met. The TOTP authentication extension allows users to be
- additionally verified against a user-specific and secret key generated during <link
- linkend="totp-enrollment">enrollment of their authentication device</link>.</para>
- <important>
- <para>This chapter involves modifying the contents of <varname>GUACAMOLE_HOME</varname> -
- the Guacamole configuration directory. If you are unsure where
- <varname>GUACAMOLE_HOME</varname> is located on your system, please consult <xref
- linkend="configuring-guacamole"/> before proceeding.</para>
- </important>
- <section xml:id="totp-prerequisites">
- <title>Prerequisites</title>
- <para>The enrollment process used by Guacamole's TOTP support needs to be able to store an
- automatically-generated key within the user's account. Another extension must be
- installed which supports storage of arbitrary data from other extensions.
- <emphasis>Currently the only extensions provided with Guacamole which support this
- kind of storage are the <link linkend="jdbc-auth">database authentication
- extensions</link>.</emphasis></para>
- <para>It is thus recommended that authentication against a database be fully configured
- prior to setting up TOTP. Instructions walking through the setup of database
- authentication for Guacamole are provided in <xref linkend="jdbc-auth"/>.</para>
- </section>
- <section xml:id="totp-architecture">
- <title>How TOTP works with Guacamole</title>
- <para>Guacamole provides support for TOTP as a second authentication factor. To make use of
- the TOTP authentication extension, some other authentication mechanism will need be
- configured, as well. When a user attempts to log into Guacamole, other installed
- authentication methods will be queried first:</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/totp-auth-factor-1.png" format="PNG"
- contentwidth="2in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- <para>Only after authentication has succeeded with one of those methods will Guacamole
- prompt the user to further verify their identity with an authentication code:</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/totp-auth-factor-2.png" format="PNG"
- contentwidth="4in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- <para>If both the initial authentication attempt and verification using TOTP succeed, the
- user will be allowed in. If either mechanism fails, access to Guacamole is
- denied.</para>
- <section xml:id="totp-enrollment">
- <title>Enrollment</title>
- <para>If the user does not yet have a TOTP key associated with their account (they have
- not yet completed enrollment), they will be required to enroll an authentication
- device after passing the first authentication factor. A QR code containing an
- automatically-generated key will be presented to the user to be scanned by their
- authentication app or device:</para>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/totp-enroll.png" format="PNG" contentwidth="4in"/>
- </imageobject>
- </mediaobject>
- <para>If the authentication device does not support scanning QR codes for enrollment,
- the details within the QR code can be revealed by clicking the "Show" link next to
- the "Details" header. These values can then be entered manually:</para>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/totp-enroll-detail.png" format="PNG"
- contentwidth="4in"/>
- </imageobject>
- </mediaobject>
- <para>Enrollment is completed once the user enters a valid authentication code generated
- by their device using the provided key.</para>
- </section>
- </section>
- <section xml:id="totp-downloading">
- <title>Downloading the TOTP extension</title>
- <para>The TOTP authentication extension is available separately from the main
- <filename>guacamole.war</filename>. The link for this and all other
- officially-supported and compatible extensions for a particular version of Guacamole are
- provided on the release notes for that version. You can find the release notes for
- current versions of Guacamole here: <link
- xlink:href="http://guacamole.apache.org/releases/"
- >http://guacamole.apache.org/releases/</link>.</para>
- <para>The TOTP authentication extension is packaged as a <filename>.tar.gz</filename> file
- containing only the extension itself,
- <filename>guacamole-auth-totp-1.3.0.jar</filename>, which must ultimately be placed in
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </section>
- <section xml:id="installing-totp-auth">
- <title>Installing TOTP authentication</title>
- <para>Guacamole extensions are self-contained <filename>.jar</filename> files which are
- located within the <filename>GUACAMOLE_HOME/extensions</filename> directory. To install
- the TOTP authentication extension, you must:</para>
- <procedure>
- <step>
- <para>Create the <filename>GUACAMOLE_HOME/extensions</filename> directory, if it
- does not already exist.</para>
- </step>
- <step>
- <para>Copy <filename>guacamole-auth-totp-1.3.0.jar</filename> within
- <filename>GUACAMOLE_HOME/extensions</filename>.</para>
- </step>
- <step>
- <para>Configure Guacamole to use TOTP authentication, as described below.</para>
- </step>
- </procedure>
- <important>
- <para>You will need to restart Guacamole by restarting your servlet container in order
- to complete the installation. Doing this will disconnect all active users, so be
- sure that it is safe to do so prior to attempting installation. If you do not
- configure the TOTP authentication properly, Guacamole will not start up again until
- the configuration is fixed.</para>
- </important>
- <section xml:id="guac-totp-config">
- <title>Configuring Guacamole for TOTP</title>
- <indexterm>
- <primary>configuring TOTP</primary>
- </indexterm>
- <indexterm>
- <primary>TOTP</primary>
- <secondary>configuration</secondary>
- </indexterm>
- <para>With the exception of <link linkend="totp-prerequisites">the storage and
- permission requirements described above</link>, the TOTP extension should work
- out-of-the-box without any additional configuration. Defaults have been chosen for
- all configuration parameters such that the TOTP extension will be compatible with
- Google Authenticator and similar, popular TOTP implementations.</para>
- <para>If your intended authentication application or device has different requirements,
- or you wish to override the defaults, additional properties may be specified within
- <filename>guacamole.properties</filename>:</para>
- <variablelist>
- <varlistentry>
- <term><property>totp-issuer</property></term>
- <listitem>
- <para>The human-readable name of the entity issuing user accounts. If not
- specified, "Apache Guacamole" will be used by default.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>totp-digits</property></term>
- <listitem>
- <para>The number of digits which should be included in each generated TOTP
- code. Legal values are 6, 7, or 8. By default, 6-digit codes are
- generated.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>totp-period</property></term>
- <listitem>
- <para>The duration that each generated code should remain valid, in seconds.
- By default, each code remains valid for 30 seconds.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><property>totp-mode</property></term>
- <listitem>
- <para>The hash algorithm that should be used to generate TOTP codes. Legal
- values are "sha1", "sha256", and "sha512". By default, "sha1" is
- used.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section xml:id="completing-totp-install">
- <title>Completing the installation</title>
- <para>Guacamole will only reread <filename>guacamole.properties</filename> and load
- newly-installed extensions during startup, so your servlet container will need to be
- restarted before TOTP authentication will take effect. Restart your servlet
- container and give the new authentication a try.</para>
- <para>
- <important>
- <para>You only need to restart your servlet container. <emphasis>You do not need
- to restart <package>guacd</package></emphasis>.</para>
- <para><package>guacd</package> is completely independent of the web application
- and does not deal with <filename>guacamole.properties</filename> or the
- authentication system in any way. Since you are already restarting the
- servlet container, restarting <package>guacd</package> as well technically
- won't hurt anything, but doing so is completely pointless.</para>
- </important>
- </para>
- <para>If Guacamole does not come back online after restarting your servlet container,
- check the logs. Problems in the configuration of the TOTP extension may prevent
- Guacamole from starting up, and any such errors will be recorded in the logs of your
- servlet container.</para>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/troubleshooting.xml b/src/chapters/troubleshooting.xml
deleted file mode 100644
index 3d253bd..0000000
--- a/src/chapters/troubleshooting.xml
+++ /dev/null
@@ -1,696 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter xml:id="troubleshooting" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Troubleshooting</title>
- <indexterm>
- <primary>troubleshooting</primary>
- </indexterm>
- <indexterm>
- <primary>errors</primary>
- </indexterm>
- <section xml:id="not-working">
- <title>It isn't working</title>
- <para>If Guacamole isn't working, chances are something isn't configured
- properly, or something is wrong with the network. Thankfully,
- Guacamole and all its components log errors thoroughly, so the
- problem can usually be traced down fairly easily if you know where
- to look. Troubleshooting Guacamole usually boils down to checking
- either syslog or your servlet container's logs (likely
- Tomcat).</para>
- <para>Failing all that, you can always post a question in the forums, or
- if you truly feel you've discovered a bug, you can create a new
- ticket in Trac. Beware that if something isn't working, and there
- are errors in the logs describing the problem, it is usually not a
- bug, and the best place to handle such things is through consulting
- this guide or the forums.</para>
- <section>
- <title>No graphics appear</title>
- <indexterm>
- <primary>Connecting, waiting for first update...</primary>
- </indexterm>
- <indexterm>
- <primary>proxies</primary>
- </indexterm>
- <para>If you <emphasis>never</emphasis> see any graphics appear, or you see "Connecting,
- waiting for first update..." for a while and then are disconnected, the most likely
- cause is a proxy.</para>
- <para>Guacamole relies on streaming data to you over a persistent connection. If
- software between Guacamole and your browser is buffering all incoming data, such as
- a proxy, this data never makes it to your browser, and you will just see it wait
- indefinitely. Eventually, thinking the client has disconnected, Guacamole closes the
- connection, at which point the proxy finally flushes its buffer and you see
- graphics! ... just in time to see it disconnect.</para>
- <para>The solution here is to either modify your proxy settings to flush packets
- immediately as they are received, or to use HTTPS. Proxies are required to pass
- HTTPS through untouched, and this usually solves the problem.</para>
- <para>Even if you aren't aware of any proxy, there may be one in place. Corporate
- firewalls very often incorporate proxies. Antivirus software may buffer incoming
- data until the connection is closed and the data is scanned for viruses.
- Virtualization software may detect HTTP data and buffer the connection just like a
- proxy. If all else fails, try HTTPS - it's the only secure way to do this
- anyway.</para>
- </section>
- <section>
- <title>Connections involving Unicode don't work</title>
- <indexterm>
- <primary>Unicode</primary>
- </indexterm>
- <indexterm>
- <primary>UTF-8</primary>
- </indexterm>
- <indexterm>
- <primary><code>URIEncoding</code></primary>
- </indexterm>
- <para>If you are using Tomcat, beware that you <emphasis>must</emphasis> set the
- <code>URIEncoding="UTF-8"</code> attribute on all connectors in your
- <filename>server.xml</filename>. If you are using a different servlet container,
- you need to find out whether it requires special options to support UTF-8 in URIs,
- and change the required settings to enable such support.</para>
- <para>Without UTF-8 support enabled for URIs, Unicode characters in connection names
- will not be received properly when connecting, and Guacamole will thing the
- connection you requested does not exist. Similarly, if you are using the built-in
- administration interface, parameters involving Unicode characters will not save
- properly without these options enabled.</para>
- </section>
- </section>
- <section xml:id="syslog">
- <title>syslog</title>
- <indexterm>
- <primary>syslog</primary>
- </indexterm>
- <para>guacd and libguac-based programs (such as all client plugins) log
- informational messages and errors to syslog. Specifically, guacd
- uses syslog, and it exposes this logging facility to everything it
- loads (client plugins), thus if the VNC or RDP support plugins
- encounter errors, they log those errors over the logging facilities
- exposed by guacd, in this case syslog.</para>
- <para>Once you guacd is started, you'll see entries like the following
- in syslog:</para>
- <informalexample>
- <screen>guacd[19663]: Guacamole proxy daemon (guacd) version 0.7.0
-guacd[19663]: Unable to bind socket to host ::1, port 4823: Address family
- not supported by protocol
-guacd[19663]: Successfully bound socket to host 127.0.0.1, port 4823
-guacd[19663]: Exiting and passing control to PID 19665
-guacd[19665]: Exiting and passing control to PID 19666
-guacd[19666]: Listening on host 127.0.0.1, port 4823</screen>
- </informalexample>
- <para>Each entry relevant to Guacamole has the prefix "guacd", denoting
- the program that produced the entry, followed by the process ID,
- followed by the message. The entries above show guacamole starting
- successfully and listening on a non-default port 4823.</para>
- <section xml:id="guacd-errors">
- <title>guacd errors</title>
- <indexterm>
- <primary>errors</primary>
- <secondary>guacd</secondary>
- </indexterm>
- <indexterm>
- <primary>guacd</primary>
- <secondary>errors</secondary>
- </indexterm>
- <section>
- <title>Unable to bind socket to any addresses.</title>
- <para>This means that guacd failed to start up at all because
- the port it wants to listen on is already taken at all
- addresses attempted. The details of what guacd tried will be
- listed in the log entries above this. To solve the problem,
- find what port guacd was trying to listen on (the default is
- 4822) and check if any other service is listening on that
- port.</para>
- <para>If another service is listening on the default port, you
- can always specify a non-standard port for guacd by using
- the <option>-l<replaceable> PORT</replaceable></option>
- option (that's a lowercase "L", not a number "1"), where
- <replaceable>PORT</replaceable> is the number of the
- port to listen on. Beware that you will likely have to
- modify <filename>guacamole.properties</filename> so that
- Guacamole knows how to connect to guacd.</para>
- </section>
- <section>
- <title>Unable to start <replaceable>input</replaceable>
- thread</title>
- <para>guacd creates two threads for each connection: one that
- receives input from the connected client, and the other that
- produces output for the client. If either of these fails to
- start, the above error will be logged along with the
- cause.</para>
- <para>If it is the output thread that fails to start, the
- message will instead read: "Unable to start output
- thread".</para>
- </section>
- <section>
- <title>Client finished abnormally</title>
- <para>If the client plugin ever returns an error code, this will
- cause the connection to immediately terminate, with the
- cause of the error specific to the plugin in use. The cause
- should be detailed in the log messages above the error. If
- those log messages don't make sense, you may have found a
- bug.</para>
- </section>
- <section>
- <title>Could not fork()
- <replaceable>parent</replaceable></title>
- <para>When guacd starts up, it immediately attempts to "fork"
- into the background (unless instructed otherwise). The word
- "fork()" above is a reference to the C function call that
- does this. There are several calls to this function, each of
- which might fail if system resources are lacking or
- something went wrong at a low level. If you see this
- message, it is probably not a bug in Guacamole, but rather a
- problem with the load level of your system.</para>
- <para>This message may also appear as "Could not fork() group
- leader".</para>
- </section>
- <section>
- <title>Unable to change working directory to /</title>
- <para>One of the duties of guacd as it starts up is to change
- its working directory to the root directory. This is to
- prevent locking the current directory in case it needs to be
- unmounted, etc. If guacd cannot do this, this error will be
- logged, along with the cause.</para>
- </section>
- <section>
- <title>Unable to redirect standard file descriptors to
- /dev/null</title>
- <para>As guacd starts, it also has to redirect STDOUT, STDERR,
- and STDIN to <filename>/dev/null</filename> such that
- attempts to use these output mechanisms do not pollute the
- active console. Though guacd and client plugins will use the
- exposed logging facilities (and thus syslog) rather than
- STDOUT or STDERR, libraries used by client plugins are often
- written only from the mindset of a typical client, and use
- standard output mechanisms for debug logging. Not
- redirecting these would result in undesired output to the
- console.</para>
- <para>If guacd cannot redirect these file descriptors for any
- reason, this error will be logged, along with the
- cause.</para>
- </section>
- <section>
- <title>Error parsing given address or port:
- <replaceable>HOSTNAME</replaceable></title>
- <para>If you specified a host or port to listen on via
- commandline options, and that host or port is actually
- invalid, you will see this error. Fix the corresponding
- option and try again.</para>
- </section>
- <section>
- <title>Error opening socket</title>
- <para>When guacd starts up, it needs to open a socket and then
- listen on that socket. If it can't even open the socket,
- this error will be logged, and guacd will exit. The cause is
- most likely related to permissions, and is logged along with
- the error.</para>
- </section>
- <section>
- <title>Unable to resolve host</title>
- <para>If the hostname you specified on the commandline cannot be
- found, you will see this error. Note that this error is from
- guacd, and does not relate to whatever remote desktop
- servers you may be trying to use; it relates only to the
- host guacd is trying to listen on. Check the hostname or IP
- address specified on the commandline. If that checks out,
- there may be a problem with your DNS or your network.</para>
- </section>
- <section>
- <title>Could not become a daemon</title>
- <para>In order to become a "daemon" (that is, in order to run in
- the background as a system process), guacd must create and
- exit from several processes, redirect file descriptors, etc.
- If any of these steps fails, guacd will not become a daemon,
- and it will log this message and exit. The reason guacd
- could not become a daemon will be in the previous error
- message in the logs.</para>
- </section>
- <section>
- <title>Could not write PID file</title>
- <para>guacd offers a commandline option that lets you specify a
- file that it should write its process ID into, which is
- useful for init scripts. If you see this error, it likely
- means the user guacd is running as does not have permission
- to write this file. The true cause of the error will be
- logged in the same entry. Check which user guacd is running
- as, and then check that it has write permission to the file
- in question.</para>
- </section>
- <section>
- <title>Could not listen on socket</title>
- <para>When guacd starts up, it needs to listen on the socket it
- just opened in order to accept connections. If it cannot
- listen on the socket, clients will be unable to connect. If,
- for any reason, guacd is unable to listen on the socket,
- guacd will exit and log this message along with the cause,
- which is most likely a low-level system resource
- problem.</para>
- </section>
- <section>
- <title>Could not accept client connection</title>
- <para>When a client connects to guacd, it must accept the
- connection in order for communication to ensue. If it cannot
- even accept the connection, no communication between server
- and client will happen, and this error will be logged. The
- cause of the error will be logged in the same entry.
- Possible causes include permissions problems, or lack of
- server resources.</para>
- </section>
- <section>
- <title>Error forking child process</title>
- <para>When a client connects to guacd, it must create a new
- process to handle the connection while the old guacd process
- continues to listen for new connections. If, for any reason,
- guacd cannot create this process, the connection from that
- client will be denied, and the cause of the error will be
- logged. Possible causes include permissions problems, or
- lack of server resources.</para>
- </section>
- <section>
- <title>Error closing daemon reference to child
- descriptor</title>
- <para>When guacd receives a connection, and it creates a new
- process to handle that connection, it gains a copy of the
- file descriptor that the client will use for communication.
- As this connection can never be closed unless all references
- to the descriptor are closed, the server must close its copy
- such that the client is the only remaining holder of the
- file descriptor. If the server cannot close the descriptor,
- it will log this error message along with the cause.</para>
- </section>
- <section>
- <title>Error sending "sync" instruction</title>
- <para>During the course of a Guacamole session, guacd must
- occasionally "ping" the client to make sure it is still
- alive. This ping takes the form of a "sync" instruction,
- which the client is obligated to respond to as soon as it is
- received. If guacd cannot send this instruction, this error
- will be logged, along with the cause. Chances are the
- connection has simply been closed, and this error can be
- ignored.</para>
- </section>
- <section>
- <title>Error flushing output</title>
- <para>After the client plugin is finished (for the time being)
- with handling server messages, the socket is automatically
- flushed. If the server cannot flush this socket for some
- reason, such as the connection already being closed, you
- will see this error. Normally, this error does not indicate
- a problem, but rather that the client has simply closed the
- connection.</para>
- </section>
- <section>
- <title>Error handling server messages</title>
- <para>While the client plugin is running, guacd will
- occasionally ask the plugin to check and handle any messages
- that it may have received from the server it connected to.
- If the client plugin fails for some reason while doing this,
- this error will be logged, and the cause of the error will
- likely be logged in previous log entries by the client
- plugin.</para>
- </section>
- <section>
- <title>Error reading instruction</title>
- <para>During the course of a Guacamole session, instructions are
- sent from client to server which are to be handled by the
- client plugin. If an instruction cannot be read, this error
- will be logged. Usually this means simply that the
- connection was closed, but it could also indicate that the
- version of the client in use is so old that it doesn't
- support the current Guacamole protocol at all. If the cause
- looks like the connection was closed (end of stream reached,
- etc.), this log entry can be ignored. Otherwise, if the
- first two numbers of the version numbers of all Guacamole
- components match, you have probably found a bug.</para>
- </section>
- <section>
- <title>Client instruction handler error</title>
- <para>This error indicates that a client plugin failed inside
- the handler for a specific instruction. When the server
- receives instructions from the client, it then invokes
- specific instruction handles within the client plugin. In
- general, this error is not useful to a user or system
- administrator. If the cause looks benign, such as reaching
- the end of a stream (the connection closed), it can be
- ignored as normal. Otherwise, this error can indicate a bug
- either in the client plugin or in a library used by the
- client plugin.</para>
- <para>It can also indicate a problem in the remote desktop
- server which is causing the client plugin to fail while
- communicating with it.</para>
- </section>
- <section>
- <title>Error reading "<replaceable>OPCODE</replaceable>"</title>
- <para>During the handshake of the Guacamole protocol, the server
- expects a very specific sequence of instructions to be
- received. If the wrong instructions are received, or the
- connection is abruptly closed during the handshake, the
- above error will occur.</para>
- <para>In the case that the cause is the connection closing, this
- is normal, and probably just means that the client
- disconnected before the initial handshake completed.</para>
- <para>If the connection was not closed abruptly, but instead the
- wrong instruction was received, this could mean either that
- the connecting client is from an incompatible version of
- Guacamole (and thus does not know the proper handshake
- procedure) or you have found a bug. Check whether all
- installed components came from the same upstream release
- bundle.</para>
- </section>
- <section>
- <title>Error sending "args"</title>
- <para>During the handshake of the Guacamole protocol, the server
- must expose all parameters used by the client plugin via the
- args instruction. If this cannot be sent, you will see this
- error in the logs. The cause will be included in the error
- message, and usually just indicates that the connection was
- closed during the handshake, and thus the handshake cannot
- continue.</para>
- </section>
- <section>
- <title>Error loading client plugin</title>
- <para>When the client connects, it sends an instruction to guacd
- informing it what protocol it wishes to use. If the
- corresponding client plugin cannot be found or used for any
- reason, this message will appear in the logs. Normally this
- indicates that the corresponding client plugin is not
- actually installed. The cause listed after the error message
- will indicate whether this is the case.</para>
- </section>
- <section>
- <title>Error instantiating client</title>
- <para>After the client plugin is loaded, an initialization
- function provided by the client plugin is invoked. If this
- function fails, then the client itself cannot be created,
- and this error will be logged. Usually this indicates that
- one or more of the parameters given to the client plugin are
- incorrect or malformed. Check the configuration of the
- connection in use at the time.</para>
- </section>
- </section>
- <section xml:id="libguac-client-vnc-errors">
- <title>libguac-client-vnc errors</title>
- <section>
- <title>Error waiting for VNC message</title>
- <para>The VNC client plugin must wait for messages sent by the
- VNC server, and handle them when they arrive. If there was
- an error while waiting for a message from the VNC server,
- this error message will be displayed. Usually this means
- that the VNC server closed the connection, or there is a
- problem with the VNC server itself, but the true cause of
- the error will be logged.</para>
- </section>
- <section>
- <title>Error handling VNC server message</title>
- <para>When messages are received from the VNC server,
- libvncclient must handle them and then invoke the functions
- of libguac-client-vnc as necessary. If libvncclient fails
- during the handling of a received message, this error will
- be logged, along with (hopefully) the cause. This may
- indicate a problem with the VNC server, or a lack of support
- within libvncclient.</para>
- </section>
- <section>
- <title>Wrong argument count received</title>
- <para>The connecting client is required to send exactly the same
- number of arguments as requested by the client plugin. If
- you see this message, it means there is a bug in the client
- connecting to guacd, most likely the web application.</para>
- </section>
- </section>
- <section xml:id="libguac-client-rdp-errors">
- <title>libguac-client-rdp errors</title>
- <section>
- <title>Invalid <replaceable>parameter</replaceable></title>
- <para>If one of the parameters given, such as "width", "height",
- or "color-depth", is invalid (not an integer, for example),
- you will receive this error. Check the parameters of the
- connection in use and try again.</para>
- </section>
- <section>
- <title>Support for the CLIPRDR channel (clipboard redirection) could not be
- loaded</title>
- <para>FreeRDP provides a plugin which provides clipboard support for RDP. This
- plugin is typically built into FreeRDP, but some distributions may bundle this
- separately. libguac-client-rdp loads this plugin in order to support clipboard,
- as well. If this plugin could not be loaded, then clipboard support will not be
- available, and the reason will be logged.</para>
- </section>
- <section>
- <title>Cannot create static channel "<replaceable>name</replaceable>": failed to
- load "guac-common-svc" plugin for FreeRDP</title>
- <para>RDP provides support for much of its feature set through static virtual
- channels. Sound support, for example is provided through the "RDPSND" channel.
- Device redirection for printers and drives is provided through "RDPDR". To
- support these and other static virtual channels, libguac-client-rdp builds a
- plugin for FreeRDP called "guac-common-svc" which allows Guacamole to hook into
- the parts of FreeRDP that support virtual channels.</para>
- <para>If libguac-client-rdp cannot load this plugin, support for any features which
- leverage static virtual channels will not work, and the reason will be logged. A
- likely explanation is that libguac-client-rdp was built from source, and the
- directory specified for FreeRDP's installation location was incorrect. For
- FreeRDP to be able to find plugins, those plugins must be placed in the
- <filename>freerdp2/</filename> subdirectory of whichever directory contains
- the <filename>libfreerdp2.so</filename> library.</para>
- </section>
- <section>
- <title>Server requested unsupported clipboard data type</title>
- <para>When clipboard support is loaded, libguac-client-rdp
- informs the RDP server of all supported clipboard data
- types. The RDP server is required to send only those types
- supported by the client. If the server decides to send an
- unsupported type anyway, libguac-client-rdp ignores the data
- sent, and logs this message.</para>
- </section>
- <section>
- <title>Clipboard data missing null terminator</title>
- <para>When text is sent via a clipboard message, it is required
- to have a terminating null byte. If this is not the case,
- the clipboard data is invalid, and libguac-client-rdp
- ignores it, logging this error message.</para>
- </section>
- </section>
- </section>
- <section xml:id="servlet-container-logs">
- <title>Servlet container logs</title>
- <para>Your servlet container will have logs which the web application
- side of Guacamole will log errors to. In the case of Tomcat, this is
- usually <filename>catalina.out</filename> or
- <filename><replaceable>HOSTNAME</replaceable>.log</filename>
- (for example, <filename>localhost.log</filename>).</para>
- <section xml:id="user-mapping-xml-errors">
- <title><filename>user-mapping.xml</filename> errors</title>
- <para>Errors in the relating to the
- <filename>user-mapping.xml</filename> file usually indicate
- that either the XML is malformed, or the file itself cannot be
- found.</para>
- <section>
- <title>Attribute "name" required for connection tag</title>
- <para>If you specify a connection with a
- <code><connection></code> tag, it must have a
- corresponding name set via the <code>name</code> attribute.
- If it does not, then the XML is malformed, and this error
- will be logged. No users will be able to login.</para>
- </section>
- <section>
- <title>Attribute "name" required for param tag</title>
- <para>Each parameter specified with a <code><param></code>
- tag must have a corresponding name set via the
- <code>name</code> attribute. If it does not, then the
- XML is malformed, and this error will be logged. No users
- will be able to login.</para>
- </section>
- <section>
- <title>Unexpected character data</title>
- <para>Character data (text not within angle brackets) can only
- exist within the <code><param></code> tag. If it exists
- elsewhere, then the XML is malformed, and this error will be
- logged. No users will be able to login.</para>
- </section>
- <section>
- <title>Invalid encoding type</title>
- <para>There are only two legal values for the
- <code>encoding</code> attribute of the
- <code><authorize></code> tag: <code>plain</code>
- (indicating plain text) and <code>md5</code> (indicating a
- value hashed with the MD5 digest). If any other value is
- used, then the XML is malformed, and this error will be
- logged. No users will be able to login.</para>
- </section>
- <section>
- <title>User mapping could not be read</title>
- <para>If for any reason the user mapping file cannot be read
- (the servlet container lacks read permission for the file,
- the file does not exist, etc.), this error will be logged.
- Check <filename>guacamole.properties</filename> to see where
- the user mapping file is specified to exist, and then check
- that is both exists and is readable by your servlet
- container.</para>
- </section>
- </section>
- <section xml:id="guacamole-properties-errors">
- <title><filename>guacamole.properties</filename> errors</title>
- <para>If a property is malformed or a required property is missing,
- an error describing the problem will be logged.</para>
- <section>
- <title>Property <replaceable>PROPERTY</replaceable> is
- required</title>
- <para>If Guacamole or an extension of Guacamole requires a
- specific property in
- <filename>guacamole.properties</filename>, but this
- property is not defined, this error will be logged. Check
- which properties are required by the authentication provider
- (or other extensions) in use, and then compare that against
- the properties within
- <filename>guacamole.properties</filename>.</para>
- </section>
- <section>
- <title>Specified authentication provider class is not a
- AuthenticationProvider</title>
- <para>The <code>auth-provider</code> property allows you to
- specify a custom authentication provider class which will
- handle all authentication, but these classes must implement
- the <classname>AuthenticationProvider</classname> interface.
- If the class specified does not, this error will be logged.
- Check that your authentication provider class implements
- <classname>AuthenticationProvider</classname> (if you
- implemented it yourself), and verify that you are specifying
- the correct class.</para>
- <para>If you are certain that the class specified is correct,
- you may have placed the .jar file for your authentication
- provider in the wrong directory. Make sure the .jar file is
- in the directory specified by the <code>lib-directory</code>
- parameter in guacamole.properties.</para>
- </section>
- <section>
- <title>Resource /guacamole.properties not found</title>
- <para>Guacamole requires that the
- <filename>guacamole.properties</filename> file is in the
- classpath of your servlet container. If it is not, this
- error will be logged. Check that
- <filename>guacamole.properties</filename> is in the
- proper location, and then restart your servlet
- container.</para>
- </section>
- <section>
- <title>Missing "basic-user-mapping" parameter required for basic
- login</title>
- <para>If you are using the authentication provider included with
- Guacamole, it requires the <code>basic-user-mapping</code>
- property to be set. If this property is missing, you will
- see this error. Add the missing property to
- <filename>guacamole.properties</filename>, restart your
- servlet container, and try again.</para>
- </section>
- </section>
- <section xml:id="guacamole-auth-errors">
- <title>Authentication errors</title>
- <para>If someone attempts to login with invalid credentials, or
- someone attempts to access a resource or connection that does
- not exist or they do not have access to, errors regarding the
- invalid attempt will be logged.</para>
- <section>
- <title>Cannot connect - user not logged in</title>
- <para>A user attempted to connect using the HTTP tunnel, and
- while the tunnel does exist and is attached to their
- session, they are not actually logged in. Normally, this
- isn't strictly possible, as a user has to have logged in for
- a tunnel to be attached to their session, but as it isn't an
- impossibility, this error does exist. If you see this error,
- it could mean that the user logged out at the same time that
- they made a connection attempt.</para>
- </section>
- <section>
- <title>Requested configuration is not authorized</title>
- <para>A user attempted to connect to a configuration with a
- given ID, and while that configuration does exist, they are
- not authorized to use it. This could mean that the user is
- trying to access things they have no privileges for, or that
- they are trying to access configurations they legitimately
- should, but are actually logged out.</para>
- </section>
- <section>
- <title>User has no session</title>
- <para>A user attempted to access a page that needs data from
- their session, but their session does not actually exist.
- This usually means the user has not logged in, as sessions
- are created through the login process.</para>
- </section>
- </section>
- <section xml:id="guacamole-tunnel-errors">
- <title>Tunnel errors</title>
- <para>The tunnel frequently returns errors if guacd is killed, the
- connection is closed, or the client abruptly closes the
- connection.</para>
- <section>
- <title>No such tunnel</title>
- <para>An attempt was made to use a tunnel which does not
- actually exist. This is usually just the JavaScript client
- sending a leftover message or two while it hasn't realized
- that the server has disconnected. If this error happens
- consistently and is associated with Guacamole generally not
- working, it could be a bug.</para>
- </section>
- <section>
- <title>No tunnel created</title>
- <para>A connection attempt for a specific configuration was
- made, but the connection failed, and no tunnel was created.
- This is usually because the user was not authorized to use
- that connection, and thus no tunnel was created for access
- to that connection.</para>
- </section>
- <section>
- <title>No query string provided</title>
- <para>When the JavaScript client is communicating with the HTTP
- tunnel, it <emphasis>must</emphasis> provide data in the
- query string describing whether it wants to connect, read,
- or write. If this data is missing as the error indicates,
- there is a bug in the HTTP tunnel.</para>
- </section>
- <section>
- <title>Tunnel reached end of stream</title>
- <para>An attempt to read from the tunnel was made, but the
- tunnel in question has already reached the end of stream
- (the connection is closed). This is mostly an informative
- error, and can be ignored.</para>
- </section>
- <section>
- <title>Tunnel is closed</title>
- <para>An attempt to read from the tunnel was made, but the
- tunnel in question is already closed. This can happen if the
- client or guacd have closed the connection, but the client
- has not yet settled down and is still making read attempts.
- As there can be lags between when connections close and when
- the client realizes it, this can be safely ignored.</para>
- </section>
- <section>
- <title>End of stream during initial handshake</title>
- <para>If guacd closes the connection suddenly without allowing
- the client to complete the initial handshake required by the
- Guacamole protocol, this error will appear in the logs. If
- you see this error, you should check syslog for any errors
- logged by guacd to determine why it closed the connection so
- early.</para>
- </section>
- <section>
- <title>Element terminator of instruction was not ';' nor
- ','</title>
- <para>The Guacamole protocol imposes a strict format which
- requires individual parts of instructions (called
- "elements") to end with either a ";" or "," character. If
- they do not, then something has gone wrong during
- transmission. This usually indicates a bug in the client
- plugin in use, guacd, or libguac.</para>
- </section>
- <section>
- <title>Non-numeric character in element length</title>
- <para>The Guacamole protocol imposes a strict format which
- requires each element of an instruction to have a length
- prefix, which must be composed entirely of numeric
- characters (digits 0 through 9). If a non-numeric character
- is read, then something has gone wrong during transmission.
- This usually indicates a bug in the client plugin in use,
- guacd, or libguac.</para>
- </section>
- </section>
- </section>
-</chapter>
diff --git a/src/chapters/using.xml b/src/chapters/using.xml
deleted file mode 100644
index a57181a..0000000
--- a/src/chapters/using.xml
+++ /dev/null
@@ -1,516 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="using-guacamole"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
-
- <title>Using Guacamole</title>
- <para><indexterm>
- <primary>interacting</primary>
- </indexterm>Guacamole provides access to much of the functionality of a desktop from within
- your web browser. Although most people use remote desktop tools only when absolutely
- necessary, we believe that Guacamole must be aimed at becoming a primary means of accessing
- desktops, and the interface is thus intended to be as seamless and unobtrusive as
- possible.</para>
- <section xml:id="home-screen">
- <title>Home screen</title>
- <para>Once you have successfully logged in, you will be taken to either the Guacamole home
- screen, where all available connections are listed, or directly to a connection, if you
- only have access to one connection.</para>
- <para>The home screen will contain a list of all connections to which you have access, along
- with thumbnails of any recently used or active connections. If you have access to a
- large number of connections and wish to quickly locate a specific connection, you can
- also enter search terms within the "Filter" field to filter the list of connections by
- name.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guacamole-home-screen.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>The Guacamole home screen. The user menu and several recently-used
- connections are visible, along with one active connection.</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <para>Clicking on any connection will open that connection within the current window or tab,
- but multiple connections can be used simultaneously. You can easily navigate back to the
- home screen without disconnecting by using your browsers back button or the "Home"
- button in the Guacamole menu. Each connection you use will remain active until
- explicitly disconnected, or until you navigate away from Guacamole entirely. Active
- connections can be seen as thumbnails updating in real-time on the home screen.</para>
- <section xml:id="user-menu">
- <title>User menu</title>
- <para>With the exception of the client screen discussed below, all Guacamole screens
- contain a menu in the upper-right corner called the "user menu". This menu displays
- your username and contains several options which depend on your user's level of
- access:</para>
- <variablelist>
- <varlistentry>
- <term>Home</term>
- <listitem>
- <para>Navigates back to the home screen, if you are not already there. If
- you only have access to one connection, this will be replaced with a
- link to that connection.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Settings</term>
- <listitem>
- <para>Navigates to the settings interface, which provides access to user
- preferences such as display language. If you have access to
- administrative functions, those are found within the settings interface,
- as well, and are discussed in more detail in <xref
- linkend="administration"/>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Logout</term>
- <listitem>
- <para>Logs out of Guacamole completely, closing all current connections and
- ending the Guacamole session.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </section>
- <section xml:id="client-screen">
- <title>Client screen</title>
- <para>Once you open a connection, you will see a real-time view of the remote display. You
- can interact with this display just as you would your normal desktop. Your mouse and
- keyboard will function as if they were connected directly to the remote machine.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guacamole-client-interface.png" format="PNG"
- contentwidth="6in"/>
- </imageobject>
- <caption>
- <para>Guacamole client interface, with the Guacamole menu open.</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <para>The remote display will take up the entire browser window, with no buttons or menus to
- disturb the view. With the intent of providing a seamless experience, options specific
- to remote desktop are hidden within the Guacamole menu, which can be opened as
- needed.</para>
- <section xml:id="guacamole-menu">
- <title>The Guacamole menu</title>
- <para>The Guacamole menu is a sidebar which is hidden until explicitly shown. On a
- desktop or other device which has a hardware keyboard, you can show this menu by
- pressing <keycombo>
- <keycap>Ctrl</keycap>
- <keycap>Alt</keycap>
- <keycap>Shift</keycap>
- </keycombo>. If you are using a mobile or touchscreen device that lacks a keyboard,
- you can also show the menu by swiping right from the left edge of the screen. To
- hide the menu, you press <keycombo>
- <keycap>Ctrl</keycap>
- <keycap>Alt</keycap>
- <keycap>Shift</keycap>
- </keycombo> again or swipe left across the screen.</para>
- <para>The Guacamole menu provides options for:<itemizedlist>
- <listitem>
- <para>Navigating back to the home screen</para>
- </listitem>
- <listitem>
- <para>Sharing the current connection</para>
- </listitem>
- <listitem>
- <para>Reading from (and writing to) the clipboard of the remote
- desktop</para>
- </listitem>
- <listitem>
- <para>Uploading and downloading files</para>
- </listitem>
- <listitem>
- <para>Selecting alternative methods of typing or controlling the mouse,
- particularly for use on mobile or touchscreen devices</para>
- </listitem>
- <listitem>
- <para>Zooming in and out of the remote display</para>
- </listitem>
- <listitem>
- <para>Disconnecting from the current connection entirely</para>
- </listitem>
- </itemizedlist></para>
- </section>
- </section>
- <section xml:id="using-the-clipboard">
- <title>Copying/pasting text</title>
- <para><indexterm>
- <primary>clipboard</primary>
- </indexterm>At the top of the Guacamole menu is a text area labeled "clipboard" along
- with some basic instructions:</para>
- <blockquote>
- <para>Text copied/cut within Guacamole will appear here. Changes to the text below will
- affect the remote clipboard.</para>
- </blockquote>
- <para>The text area functions as an interface between the remote clipboard and the local
- clipboard. Text from the local clipboard can be pasted into the text area, causing that
- text to be sent to the clipboard of the remote desktop. Similarly, if you copy or cut
- text within the remote desktop, you will see that text within the text area, and can
- manually copy it into the local clipboard if desired.</para>
- </section>
- <section xml:id="client-user-menu">
- <title>Disconnecting and navigation</title>
- <para>When you are done using the current connection, or you wish to navigate elsewhere
- temporarily, options to do so are within the user menu inside the Guacamole menu:</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guac-menu-disconnect.png" format="PNG"
- contentwidth="6in"/>
- </imageobject>
- <caption>
- <para>The user menu within the Guacamole menu.</para>
- </caption>
- </mediaobject>
- <para>The user menu within the Guacamole menu provides an additional "Disconnect" option
- that allows you to explicitly close the current connection only. Clicking "Logout"
- will also implicitly disconnect all active connections, including the current
- connection.</para>
- <para>Navigating back to the home screen or to the settings screen will not disconnect
- you: your connection will continue running in the background while you change
- settings or initiate another connection, and you can resume any active connection by
- clicking on it within the home screen.</para>
- </informalfigure>
- </section>
- <section xml:id="client-share-menu">
- <title>Sharing the connection</title>
- <para>If the Guacamole server is configured to allow connection sharing, and you have been
- granted permission to share the current connection, an additional "Share" menu will
- appear next to your username in the Guacamole menu. Clicking on this menu opens a list
- of options for sharing the current connection.</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guac-menu-share.png" format="PNG" contentwidth="6in"
- />
- </imageobject>
- </mediaobject>
- </informalfigure>
- <para>Clicking any of the options within the "Share" menu will immediately generate a unique
- share link which can be distributed to anyone, even to users which do not otherwise have
- accounts within the same Guacamole system.</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guac-menu-share-link.png" format="PNG"
- contentwidth="6in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- <para>When the link is visited, that user will be given temporary access to your connection,
- restricted according to the sharing option chosen. This access, and the validity of the
- link overall, lasts only until you disconnect. Once the connection is closed, the link
- ceases to be valid, and any users sharing the connection with you will be
- disconnected.</para>
- </section>
- <section xml:id="file-transfer">
- <title>Transferring files</title>
- <indexterm>
- <primary>file transfer</primary>
- </indexterm>
- <para>You can transfer files back and forth between your local computer and the remote
- desktop if it is supported by the underlying protocol and enabled on the connection.
- Currently, Guacamole supports file transfer for VNC, RDP, and SSH, using either the
- native file transfer support of the protocol or SFTP.</para>
- <para>Files can be transferred to the remote computer by dragging and dropping the files
- into your browser window, or through using the file browser located in the Guacamole
- menu.</para>
- <section xml:id="file-browser">
- <title>Using the file browser</title>
- <para>If file transfer is enabled on the connection, you will see one or more filesystem
- devices listed within the Guacamole menu. Clicking on one of the filesystems opens a
- file browser which lists the files and directories within that filesystem.</para>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/file-browser.png" format="PNG" contentwidth="3in"/>
- </imageobject>
- <caption>
- <para>The file browser within the Guacamole menu.</para>
- </caption>
- </mediaobject>
- <para>Double-clicking on any directory will change the current location of the file
- browser to that directory, updating the list of files shown as well as the
- "breadcrumbs" at the top of the file browser. Clicking on any of the directory names
- listed in the breadcrumbs will bring you back to that directory, and clicking on the
- drive icon on the far left will bring you all the way back to the root level.</para>
- <para>Downloads are initiated by double-clicking on any file shown, while uploads are
- initiated by clicking the "Upload Files" button. Clicking "Upload Files" will open a
- file browsing dialog where you can choose one or more files from your local
- computer, ultimately uploading the selected files to the directory currently
- displayed within the file browser.</para>
- <para>The state of all file uploads can be observed within the notification dialog that
- appears once an upload begins, and can be cleared once completed by clicking the
- "Clear" button. Downloads are tracked through your browser's own download
- notification system.</para>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/file-transfers.png" format="PNG" contentwidth="3in"/>
- </imageobject>
- <caption>
- <para>In-progress and completed file transfers.</para>
- </caption>
- </mediaobject>
- <para>When you are done browsing the filesystem and transferring files, click "Back" to
- return to the Guacamole menu.</para>
- </section>
- <section xml:id="rdp-virtual-drive">
- <title>The RDP virtual drive</title>
- <para>RDP provides its own native support for file transfer called "drive redirection"
- or "RDPDR". Guacamole provides support for this mechanism by emulating a virtual
- drive. Typically, this virtual drive will appear as a network drive within the RDP
- session. Files uploaded and downloaded will be preserved within this drive, even
- after disconnecting.</para>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guacamole-drive.png" format="PNG" contentwidth="5in"
- />
- </imageobject>
- <caption>
- <para>The Guacamole drive within a Windows RDP session.</para>
- </caption>
- </mediaobject>
- <para>Files can be downloaded from this drive using the file browser in the Guacamole
- menu or using the special "Download" folder within the virtual drive. All files
- dropped into this folder will automatically begin uploading to the client, and thus
- downloading through the browser.</para>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guacamole-drive-download.png" format="PNG"
- contentwidth="5in"/>
- </imageobject>
- <caption>
- <para>The Guacamole drive's "Download" folder.</para>
- </caption>
- </mediaobject>
- </section>
- <section xml:id="guacctl">
- <title><command>guacctl</command> / <command>guacget</command></title>
- <para><indexterm>
- <primary><command>guacctl</command></primary>
- </indexterm><indexterm>
- <primary><command>guacget</command></primary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary><command>guacctl</command></secondary>
- </indexterm><indexterm>
- <primary>SSH</primary>
- <secondary><command>guacget</command></secondary>
- </indexterm>In addition to traditional drag-and-drop and the file browser,
- Guacamole's SSH support can be used with the <command>guacctl</command> utility. The
- <command>guacctl</command> utility is a simple shell script <link
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://raw.githubusercontent.com/apache/guacamole-server/master/bin/guacctl"
- >included with Guacamole</link> which allows you to use and configure file
- transfer directly from the command line within the SSH session:</para>
- <informalexample>
- <screen><prompt>$</prompt> <userinput>guacctl</userinput>
-<computeroutput>guacctl 0.8.0, Guacamole SSH session control utility.
-Usage: guacctl [OPTION] [FILE]...
-
- -d, --download download each of the files listed.
- -s, --set-directory set the destination directory for future uploaded
- files.</computeroutput>
-<prompt>$</prompt> <userinput>guacctl -d <replaceable>FILENAME</replaceable></userinput>
-<prompt>$</prompt> <userinput>guacctl -s <replaceable>DIRECTORY</replaceable></userinput>
-$</screen>
- </informalexample>
- <para>For convenience, you may also create a symbolic link or alias to
- <command>guacctl</command> called <command>guacget</command>. When run as
- <command>guacget</command>, the utility behaves as if the
- <option>--download</option> option were supplied and initiates a download for
- each file specified on the command line.</para>
- </section>
- </section>
- <section xml:id="using-the-osk">
- <title>On-screen keyboard</title>
- <para>Certain key combinations are impossible to press within a web application like
- Guacamole because they are reserved by the operating system (<keycombo>
- <keycap>Ctrl</keycap>
- <keycap>Alt</keycap>
- <keycap>Del</keycap>
- </keycombo> or <keycombo>
- <keycap>Alt</keycap>
- <keycap>Tab</keycap>
- </keycombo>, for example) or by the web browser. If you press one of these reserved
- combinations, the effect will be observed locally, not remotely, and the remote desktop
- will receive only some of the keys.</para>
- <para>Guacamole provides its own, built-in on-screen keyboard which allows keys to be sent
- to the remote desktop without affecting the local system. If the device you're using
- does not have certain keys which the remote desktop depends on, such as the arrow keys
- or <keycap>Ctrl</keycap>, you can use the on-screen keyboard for this, too. You can show
- the on-screen keyboard by selecting the "On-screen keyboard" option from the
- menu.</para>
- <para>Clicking (or tapping) the buttons of the on-screen keyboard has the same effect as
- pressing the same buttons on a real keyboard, except that the operating system and
- browser will not intercept these keypresses; they will only be sent to the remote
- desktop.</para>
- </section>
- <section xml:id="scaling-display">
- <title>Scaling the display</title>
- <para><indexterm>
- <primary>zoom</primary>
- </indexterm>Guacamole will default to shrinking or expanding the remote display to fit
- the browser window exactly, but this is not necessarily ideal. If the remote display is
- much larger than your local display, the screen may be impossible to see or interact
- with. This is especially true for mobile phones, whose screens need to be small enough
- to fit in the average hand.</para>
- <para>You can scale the display on touch devices by using the familiar pinch gesture. Place
- two fingers on the screen and bring them closer together to zoom out or further apart to
- zoom in.</para>
- <para>If your device lacks a touch screen, you can also control the zoom level through the
- menu. The controls for zooming in and out are located at the bottom of the menu. The
- current zoom level is displayed between two "-" and "+" buttons which control the zoom
- level in 10% increments.</para>
- </section>
- <section xml:id="touch-devices">
- <title>Mobile or touch devices</title>
- <para>Guacamole is designed to work equally well across all HTML5 browsers, including those
- of mobile devices. It will automatically handle input from a touch screen or a
- traditional mouse (or both, if you happen to have such a gifted computer), and provides
- alternative input methods for devices which lack a physical keyboard.</para>
- <section xml:id="touch-mouse">
- <title>Mouse emulation</title>
- <para><indexterm>
- <primary>mouse</primary>
- </indexterm>In the case that your device has a touchscreen and lacks a mouse,
- Guacamole will emulate a mouse for the sake of interacting with remote desktops that
- expect mouse input. By default, Guacamole uses "absolute" mouse emulation. This
- means that the mouse pointer is positioned at the location of each tap on the
- screen.</para>
- <para>In both absolute and relative modes, you can click-and-drag by tapping the screen
- and then quickly placing your finger back down. This gesture only causes the mouse
- button to press down, but does not release it again until you lift your finger back
- up.</para>
- <section xml:id="absolute-mouse-emulation">
- <title>Absolute mode (touchscreen)</title>
- <para>Absolute mouse emulation is the default as it tends to be what people expect
- when using a touch device to interact with applications designed for mouse
- input.</para>
- <para>Each tap on the screen is translated into a left-click at that position.
- Right-clicking is accomplished through pressing and holding your finger on the
- screen. If parts of the remote display are off-screen, you can drag your finger
- around the screen to pan the off-screen parts back into view.</para>
- <para>Although absolute mouse emulation works generally well, a finger makes for a
- very inaccurate pointing device. To address this, Guacamole also provides
- "relative" mouse emulation. Relative mouse emulation provides a way to deal with
- the need for accurate pointer control, when a true pointer device is not
- present.</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/touchscreen.png" format="PNG"
- contentwidth="1.5in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
- <section xml:id="relative-mouse-emulation">
- <title>Relative mode (touchpad)</title>
- <para>Guacamole's relative mouse emulation behaves similarly to the touchpad present
- on most modern laptops. You drag your finger across the display to move the
- mouse pointer, and tap the display to left-click. The pointer moves relative to
- the motion of your finger. Right-clicking is accomplished with a two-finger tap,
- and middle-clicking with a three-finger tap. The mouse scroll wheel can be
- operated by dragging two fingers up or down.</para>
- <para>Because the relative mouse emulation reserves so many gestures for the
- different mouse buttons and actions, common touch gestures like panning and
- pinch-to-zoom will not work while relative mouse emulation is enabled. Instead,
- the screen will automatically pan to keep the mouse pointer in view, and you can
- zoom through the buttons in the menu.</para>
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/touchpad.png" format="PNG"
- contentwidth="1.5in"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
- </section>
- <section xml:id="text-input">
- <title>Typing without a physical keyboard</title>
- <para>Many mobile devices lack a physical keyboard entirely, and instead provide their
- own on-screen keyboards. As these are not true keyboards per se and do not produce
- key presses, Guacamole's text input mode is required for typing on these
- platforms.</para>
- <para>"Text input" allows input of keystrokes based on the input of text. Choosing "Text
- input" tells Guacamole to infer keystrokes by tracking text entered, rather than
- relying on actual key presses. Guacamole will instead determine the combination of
- keypresses necessary to produce the same pattern of input, including
- deletions.</para>
- <para><indexterm>
- <primary>input method editors</primary>
- </indexterm>If you wish to type via an IME (input method editor), such as those
- required for Chinese, Japanese, or Korean, text input mode is required for this as
- well. Such IMEs function through the explicit insertion of text and do not send
- traditional key presses. Using text input mode within Guacamole thus allows you to
- use a locally-installed IME, without requiring the IME to be installed on the remote
- desktop.</para>
- </section>
- </section>
- <section xml:id="preferences">
- <title>Changing preferences</title>
- <para>User preferences can be changed within the settings screen. These preferences are
- stored locally within the browser, so if you use multiple computers to access Guacamole,
- you can have different settings for each location. The settings screen allows users to
- change the language of the Guacamole interface, to change the default input method used
- by Guacamole connections, and to change the default mouse emulation mode for if a touch
- device is used. If you have sufficient permissions, you may also change your password,
- or administer the system.</para>
- <informalfigure>
- <screenshot>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/guacamole-preferences.png" format="PNG"
- contentwidth="6in"/>
- </imageobject>
- <caption>
- <para>Guacamole preferences screen.</para>
- </caption>
- </mediaobject>
- </screenshot>
- </informalfigure>
- <section xml:id="display-language">
- <title>Display language</title>
- <para>The Guacamole interface is currently available in English, Dutch, French, German,
- Italian, and Russian. By default, Guacamole will attempt to determine the
- appropriate display language by checking the language preferences of the browser in
- use. If this fails, or the browser is using a language not yet available within
- Guacamole, English will be used as a fallback.</para>
- <para>If you wish to override the current display language, you can do so by selecting a
- different language within the "Display language" field. The change will take effect
- immediately.</para>
- </section>
- <section xml:id="changing-password">
- <title>Changing your password</title>
- <para>System administrators can restrict the ability of individual users to change their
- own passwords, so this section may not always be available. If your account
- <emphasis>does</emphasis> have permission, the preferences screen will contain a
- "Change Password" section.</para>
- <para>To change your password, you must provide your current password, enter the desired
- new password, and click "Update Password". You will remain logged in, and the change
- will affect any future login attempt.</para>
- </section>
- <section xml:id="default-input-settings">
- <title>Default input settings</title>
- <para>Guacamole provides multiple keyboard input methods and multiple mouse emulation
- modes. Many of these settings are specifically useful for touch devices, while
- others are aimed mainly at traditional desktop use. By default, Guacamole will use
- the keyboard and mouse modes most commonly preferred by users, but you can change
- these defaults if they do not fit your tastes or your current device.</para>
- <para>The choices available mirror those within the Guacamole menu discussed earlier in
- this chapter, and changing these settings will affect the default values selected
- within the Guacamole menu of future connections.</para>
- </section>
- </section>
-
-</chapter>
diff --git a/src/chapters/yourown.xml b/src/chapters/yourown.xml
deleted file mode 100644
index 33aba87..0000000
--- a/src/chapters/yourown.xml
+++ /dev/null
@@ -1,544 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<chapter xml:id="writing-you-own-guacamole-app" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Writing your own Guacamole application</title>
- <indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>custom application</primary>
- </indexterm>
- <indexterm xmlns:xl="http://www.w3.org/1999/xlink">
- <primary>application</primary>
- <secondary>development</secondary>
- </indexterm>
- <para>As Guacamole is an API, one of the best ways to put Guacamole to use is by building your
- own Guacamole-driven web application, integrating HTML5 remote desktop into whatever you
- think needs it.</para>
- <para>The Guacamole project provides an example of doing this called "guacamole-example", but
- this example is already completed for you, and from a quick glance at this example, it may
- not be obvious just how easy it is to integrate remote access into a web application. This
- tutorial will walk you through the basic steps of building an HTML5 remote desktop
- application using the Guacamole API and Maven.</para>
- <section xml:id="basic-guacamole-architecture">
- <title>The basics</title>
- <para>Guacamole's architecture is made up of many components, but it's actually
- straightforward, especially from the perspective of the web application.</para>
- <para>Guacamole has a proxy daemon, guacd, which handles communication using remote desktop
- protocols, exposing those to whatever connects to it (in this case, the web application)
- using the Guacamole protocol. From where the web application is standing, it doesn't
- really matter that guacd dynamically loads protocol plugins or that it shares a common
- library allowing this; all that matters is that the web application just has to connect
- to port 4822 (where guacd listens by default) and use the Guacamole protocol. The
- architecture will take care of the rest.</para>
- <para>Thankfully, the Java side of the Guacamole API provides simple classes which already
- implement the Guacamole protocol with the intent of tunneling it between guacd and the
- JavaScript half of your web application. A typical web application leveraging these
- classes needs only the following:<orderedlist>
- <listitem>
- <para>A class which extends <classname>GuacamoleHTTPTunnelServlet</classname>,
- providing the tunnel between the JavaScript client (presumably using
- guacamole-common-js) and guacd.</para>
- <para><classname>GuacamoleHTTPTunnelServlet</classname> is an abstract class
- which is provided by the Guacamole API and already implements a fully
- functional, HTTP-based tunnel which the tunneling objects already part of
- guacamole-common-js are written to connect to. This class exists to make it
- easy for you to use Guacamole's existing and robust HTTP tunnel
- implementation.</para>
- <para>If you want to not use this class and instead use your own tunneling
- mechanism, perhaps WebSocket, this is fine; the JavaScript object mentioned
- above implements a common interface which you can also implement, and the
- Guacamole JavaScript client which is also part of guacamole-common-js will
- happily use your implementation as long as it provides that
- interface.</para>
- </listitem>
- <listitem>
- <para>A web page which includes JavaScript files from guacamole-common-js and
- uses the client and tunnel objects to connect back to the web
- application.</para>
- <para>The JavaScript API provided by the Guacamole project includes a full
- implementation of the Guacamole protocol as a client, implementations of
- HTTP and WebSocket-based tunnels, and mouse/keyboard/touch input
- abstraction. Again, as the Guacamole protocol and all parts of the
- architecture are documented here, you don't absolutely need to use these
- objects, but it will make your life easier. Mouse and keyboard support in
- JavaScript is finicky business, and the Guacamole client provided is
- well-known to work with other components in the API, being the official
- client of the project.</para>
- </listitem>
- </orderedlist></para>
- <para>That's really all there is to it.</para>
- <para>If you want authentication, the place to implement that would be in your extended
- version of <classname>GuacamoleHTTPTunnelServlet</classname>; this is what the Guacamole
- web application does. Besides authentication, there are many other things you could wrap
- around your remote desktop application, but ultimately the base of all this is simple:
- you have a tunnel which allows the JavaScript client to communicate with guacd, and you
- have the JavaScript client itself, with the hard part already provided within
- guacamole-common-js.</para>
- </section>
- <section xml:id="web-app-skeleton">
- <title>Web application skeleton</title>
- <para>As with most tutorials, this tutorial begins with creating a project skeleton that
- establishes a minimal base for the tutorial to enhance in subsequent steps.</para>
- <para>This tutorial will use Maven, which is the same build system used by the upstream
- Guacamole project. As the Guacamole project has a Maven repository for both the Java and
- JavaScript APIs, writing a Guacamole-based application using Maven is much easier; Maven
- will download and use the Guacamole API automatically.</para>
- <section>
- <title><filename>pom.xml</filename></title>
- <para>All Maven projects must have a project descriptor, the
- <filename>pom.xml</filename> file, in the root directory of the project. This
- file describes project dependencies and specific build requirements. Unlike other
- build tools like Apache Ant or GNU Autotools, Maven chooses convention over
- configuration: files within the project must be placed in specific locations, and
- the project dependencies must be fully described in the pom.xml. If this is done,
- the build will be handled automatically.</para>
- <para>The basis of this Guacamole-driven web application will be a simple HTML file
- which will ultimately become the client. While the finished product will have an
- HTTP tunnel written in Java, we don't need this yet for our skeleton. We will create
- a very basic, barebones Maven project containing only
- <filename>index.html</filename> and a web application descriptor file,
- <filename>web.xml</filename>. Once these files are in place, the project can be
- packaged into a <filename>.war</filename> file which can be deployed to your servlet
- container of choice (such as Apache Tomcat).</para>
- <para>As this skeleton will contain no Java code, it has no dependencies, and no build
- requirements beyond the metadata common to any Maven project. The
- <filename>pom.xml</filename> is thus very simple for the time being:</para>
- <informalexample>
- <programlisting><project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
- http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-tutorial</artifactId>
- <packaging>war</packaging>
- <version>1.3.0</version>
- <name>guacamole-tutorial</name>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
-
-</project></programlisting>
- </informalexample>
- </section>
- <section>
- <title><filename>WEB-INF/web.xml</filename></title>
- <para>Before the project will build, there needs to be a web application deployment
- descriptor, <filename>web.xml</filename>. This file is required by the Java EE
- standard for building the <filename>.war</filename> file which will contain the web
- application, and will be read by the servlet container when the application is
- actually deployed. For Maven to find and use this file when building the
- <filename>.war</filename>, it must be placed in the
- <filename>src/main/webapp/WEB-INF/</filename> directory.</para>
- <informalexample>
- <programlisting><?xml version="1.0" encoding="UTF-8"?>
-
-<web-app version="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
-
- <!-- Basic config -->
- <welcome-file-list>
- <welcome-file>index.html</welcome-file>
- </welcome-file-list>
-
-</web-app></programlisting>
- </informalexample>
- </section>
- <section>
- <title><filename>index.html</filename></title>
- <para>With the <filename>web.xml</filename> file in place and the skeleton
- <filename>pom.xml</filename> written, the web application will now build
- successfully. However, as the <filename>web.xml</filename> refers to a "welcome
- file" called <filename>index.html</filename> (which will ultimately contain our
- client), we need to put this in place so the servlet container will have something
- to serve. This file, as well as any other future static files, belongs within
- <filename>src/main/webapp</filename>.</para>
- <para>For now, this file can contain anything, since the other parts of our
- Guacamole-driven web application are not written yet. It is a placeholder which we
- will replace later:</para>
- <informalexample>
- <programlisting><!DOCTYPE HTML>
-<html>
-
- <head>
- <title>Guacamole Tutorial</title>
- </head>
-
- <body>
- <p>Hello World</p>
- </body>
-
-</html></programlisting>
- </informalexample>
- </section>
- <section>
- <title>Building the skeleton</title>
- <para>Once all three of the above files are in place, the web application will build,
- and can even be deployed to your servlet container. It won't do anything yet other
- than serve the <filename>index.html</filename> file, but it's good to at least try
- building the web application to make sure nothing is missing and all steps were
- followed correctly before proceeding:</para>
- <informalexample>
- <screen><prompt>$</prompt> mvn package
-<computeroutput>[INFO] Scanning for projects...
-[INFO] ------------------------------------------------------------------------
-[INFO] Building guacamole-tutorial
-[INFO] task-segment: [package]
-[INFO] ------------------------------------------------------------------------
-...
-[INFO] ------------------------------------------------------------------------
-[INFO] BUILD SUCCESSFUL
-[INFO] ------------------------------------------------------------------------
-[INFO] Total time: 4 seconds
-[INFO] Finished at: Fri Jan 11 13:04:11 PST 2013
-[INFO] Final Memory: 18M/128M
-[INFO] ------------------------------------------------------------------------</computeroutput>
-<prompt>$</prompt></screen>
- </informalexample>
- <para>Assuming you see the "<computeroutput>BUILD SUCCESSFUL</computeroutput>" message
- when you build the web application, there will be a new file,
- <filename>target/guacamole-tutorial-1.3.0.war</filename>, which
- can be deployed to your servlet container and tested. If you changed the name or
- version of the project in the <filename>pom.xml</filename> file, the name of this new
- <filename>.war</filename> file will be different, but it can still be found
- within <filename>target/</filename>.</para>
- </section>
- </section>
- <section xml:id="guacamole-skeleton">
- <title>Adding Guacamole</title>
- <para>Once we have a functional web application built, the next step is to actually add the
- references to the Guacamole API and integrate a Guacamole client into the
- application.</para>
- <section xml:id="adding-guac-to-pom">
- <title>Updating <filename>pom.xml</filename></title>
- <para>Now that we're adding Guacamole components to our project, we need to modify
- <filename>pom.xml</filename> to specify which components are being used, and
- where they can be obtained. With this information in place, Maven will automatically
- resolve dependencies and download them as necessary during the build.</para>
- <para>Regarding the build process itself, there are two main changes: we are now going
- to be using Java, and we need the JavaScript files from guacamole-common-js included
- automatically inside the <filename>.war</filename>.</para>
- <para>Guacamole requires at least Java 1.6, thus we must add a section to the
- <filename>pom.xml</filename> which describes the source and target Java
- versions:</para>
- <informalexample>
- <programlisting> ...
-
- <build>
- <plugins>
-
- <!-- Compile using Java 1.6 -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.3</version>
- <configuration>
- <source>1.6</source>
- <target>1.6</target>
- </configuration>
- </plugin>
-
- </plugins>
-
- </build>
-
- ...</programlisting>
- </informalexample>
- <para>Including the JavaScript files from an external project like guacamole-common-js
- requires using a feature of the maven war plugin called overlays. To add an overlay
- containing guacamole-common-js, we add a section describing the configuration of the
- Maven war plugin, listing guacamole-common-js as an overlay:</para>
- <informalexample>
- <programlisting> ...
-
- <build>
- <plugins>
-
- ...
-
- <!-- Overlay guacamole-common-js (zip) -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-war-plugin</artifactId>
- <version>2.6</version>
- <configuration>
- <overlays>
- <overlay>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-common-js</artifactId>
- <type>zip</type>
- </overlay>
- </overlays>
- </configuration>
- </plugin>
-
- </plugins>
-
- </build>
-
- ...</programlisting>
- </informalexample>
- <para>With the build now configured, we still need to add dependencies and list the
- repositories those dependencies can be downloaded from.</para>
- <para>As this is a web application which will use the Java Servlet API, we must
- explicitly include this as a dependency, as well as the Guacamole Java and
- JavaScript APIs:</para>
- <informalexample>
- <programlisting> ...
-
- <dependencies>
-
- <!-- Servlet API -->
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.5</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Main Guacamole library -->
- <dependency>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-common</artifactId>
- <version>1.1.0</version>
- <scope>compile</scope>
- </dependency>
-
- <!-- Guacamole JavaScript library -->
- <dependency>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-common-js</artifactId>
- <version>1.3.0</version>
- <type>zip</type>
- <scope>runtime</scope>
- </dependency>
-
- </dependencies>
-
- ...</programlisting>
- </informalexample>
- <para>The Java Servlet API will be provided by your servlet container, so Maven does not
- need to download it during the build, and it need not exist in any Maven
- repository.</para>
- <para>With these changes, the web application will still build at this point, even
- though no Java code has been written yet. You may wish to verify that everything
- still works.</para>
- <para>If the <filename>pom.xml</filename> was updated properly as described above, the
- web application should build successfully, and the Guacamole JavaScript API should
- be accessible in the <filename>guacamole-common-js/</filename> subdirectory of your
- web application after it is deployed. A quick check that you can access
- <uri>/guacamole-tutorial-1.3.0/guacamole-common-js/all.min.js</uri>
- is probably worth the effort.</para>
- </section>
- <section xml:id="simple-tunnel">
- <title>The simplest tunnel possible</title>
- <para>As with the other tutorials in this book, we will keep this simple for the sake of
- demonstrating the principles behind a Guacamole-based web application, and to give
- developers a good idea of where to start looking when it's time to consult the API
- documentation.</para>
- <para>It is the duty of the class extending
- <classname>GuacamoleHTTPTunnelServlet</classname> to implement a function called
- <methodname>doConnect()</methodname>. This is the only function required to be
- implemented, and in general it is the only function you should implement; the other
- functions involved are already optimized for tunneling the Guacamole
- protocol.</para>
- <para>The <methodname>doConnect()</methodname> function returns a
- <classname>GuacamoleTunnel</classname>, which provides a persistent
- communication channel for <classname>GuacamoleHTTPTunnelServlet</classname> to use
- when talking with guacd and initiating a connection with some arbitrary remote
- desktop using some arbitrary remote desktop protocol. In our simple tunnel, this
- configuration will be hard-coded, and no authentication will be attempted. Any user
- accessing this web application will be immediately given a functional remote
- desktop, no questions asked.</para>
- <para>Create a new file, <filename>TutorialGuacamoleTunnelServlet.java</filename>,
- defining a basic implementation of a tunnel servlet class:</para>
- <informalexample>
- <programlisting>package org.apache.guacamole.net.example;
-
-import javax.servlet.http.HttpServletRequest;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.net.GuacamoleSocket;
-import org.apache.guacamole.net.GuacamoleTunnel;
-import org.apache.guacamole.net.InetGuacamoleSocket;
-import org.apache.guacamole.net.SimpleGuacamoleTunnel;
-import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
-import org.apache.guacamole.protocol.GuacamoleConfiguration;
-import org.apache.guacamole.servlet.GuacamoleHTTPTunnelServlet;
-
-public class TutorialGuacamoleTunnelServlet
- extends GuacamoleHTTPTunnelServlet {
-
- @Override
- protected GuacamoleTunnel doConnect(HttpServletRequest request)
- throws GuacamoleException {
-
- // Create our configuration
- GuacamoleConfiguration config = new GuacamoleConfiguration();
- config.setProtocol("vnc");
- config.setParameter("hostname", "localhost");
- config.setParameter("port", "5901");
- config.setParameter("password", "potato");
-
- // Connect to guacd - everything is hard-coded here.
- GuacamoleSocket socket = new ConfiguredGuacamoleSocket(
- new InetGuacamoleSocket("localhost", 4822),
- config
- );
-
- // Return a new tunnel which uses the connected socket
- return new SimpleGuacamoleTunnel(socket);;
-
- }
-
-}</programlisting>
- </informalexample>
- <para>Place this file in the
- <filename>src/main/java/org/apache/guacamole/net/example</filename> subdirectory
- of the project. The initial part of this subdirectory,
- <filename>src/main/java</filename>, is the path required by Maven, while the
- rest is the directory required by Java based on the package associated with the
- class.</para>
- <para>Once the class defining our tunnel is created, it must be added to the
- <filename>web.xml</filename> such that the servlet container knows which URL
- maps to it. This URL will later be given to the JavaScript client to establish the
- connection back to the Guacamole server:</para>
- <informalexample>
- <programlisting> ...
-
- <!-- Guacamole Tunnel Servlet -->
- <servlet>
- <description>Tunnel servlet.</description>
- <servlet-name>Tunnel</servlet-name>
- <servlet-class>
- org.apache.guacamole.net.example.TutorialGuacamoleTunnelServlet
- </servlet-class>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>Tunnel</servlet-name>
- <url-pattern>/tunnel</url-pattern>
- </servlet-mapping>
-
- ...</programlisting>
- </informalexample>
- <para>The first section assigns a unique name, "Tunnel", to the servlet class we just
- defined. The second section maps the servlet class by it's servlet name ("Tunnel")
- to the URL we wish to use when making HTTP requests to the servlet:
- <uri>/tunnel</uri>. This URL is relative to the context root of the web
- application. In the case of this web application, the final absolute URL will be
- <uri>/guacamole-tutorial-1.3.0/tunnel</uri>.</para>
- </section>
- <section xml:id="simple-client">
- <title>Adding the client</title>
- <para>As the Guacamole JavaScript API already provides functional client and tunnel
- implementations, as well as mouse and keyboard input objects, the coding required
- for the "web" side of the web application is very minimal.</para>
- <para>We must create a <classname>Guacamole.HTTPTunnel</classname>, connect it to our
- previously-implemented tunnel servlet, and pass that tunnel to a new
- <classname>Guacamole.Client</classname>. Once that is done, and the
- <methodname>connect()</methodname> function of the client is called,
- communication will immediately ensue, and your remote desktop will be
- visible:</para>
- <informalexample>
- <programlisting> ...
- <body>
-
- <!-- Guacamole -->
- <script type="text/javascript"
- src="guacamole-common-js/all.min.js"></script>
-
- <!-- Display -->
- <div id="display"></div>
-
- <!-- Init -->
- <script type="text/javascript"> /* <![CDATA[ */
-
- // Get display div from document
- var display = document.getElementById("display");
-
- // Instantiate client, using an HTTP tunnel for communications.
- var guac = new Guacamole.Client(
- new Guacamole.HTTPTunnel("tunnel")
- );
-
- // Add client to display div
- display.appendChild(guac.getDisplay().getElement());
-
- // Error handler
- guac.onerror = function(error) {
- alert(error);
- };
-
- // Connect
- guac.connect();
-
- // Disconnect on close
- window.onunload = function() {
- guac.disconnect();
- }
-
- /* ]]> */ </script>
-
- </body>
- ...</programlisting>
- </informalexample>
- <para>If you build and deploy the web application now, it will work, but mouse and
- keyboard input will not. This is because input is not implemented by the client
- directly. The Guacamole.Client object only decodes the Guacamole protocol and
- handles the display, providing an element which you can add manually to the DOM.
- While it will also send keyboard and mouse events for you, you need to call the
- respective functions manually. The Guacamole API provides keyboard and mouse
- abstraction objects which make this easy.</para>
- <para>We need only create a <classname>Guacamole.Mouse</classname> and
- <methodname>Guacamole.Keyboard</methodname>, and add event handlers to handle
- their corresponding input events, calling whichever function of the Guacamole client
- is appropriate to send the input event through the tunnel to guacd:</para>
- <informalexample>
- <programlisting> ...
-
- <!-- Init -->
- <script type="text/javascript"> /* <![CDATA[ */
-
- ...
-
- // Mouse
- var mouse = new Guacamole.Mouse(guac.getDisplay().getElement());
-
- mouse.onmousedown =
- mouse.onmouseup =
- mouse.onmousemove = function(mouseState) {
- guac.sendMouseState(mouseState);
- };
-
- // Keyboard
- var keyboard = new Guacamole.Keyboard(document);
-
- keyboard.onkeydown = function (keysym) {
- guac.sendKeyEvent(1, keysym);
- };
-
- keyboard.onkeyup = function (keysym) {
- guac.sendKeyEvent(0, keysym);
- };
-
- /* ]]> */ </script>
-
- ...</programlisting>
- </informalexample>
- </section>
- </section>
- <section xml:id="next-steps">
- <title>Where to go from here</title>
- <para>At this point, we now have a fully functional Guacamole-based web application. This
- web application inherits all the core functionality present in the official Guacamole
- web application, including sound and video, without very much coding.</para>
- <para>Extending this application to provide authentication, multiple connections per user,
- or a spiffy interface which is compatible with mobile is not too much of a stretch. This
- is exactly how the Guacamole web application is written. Integrating Guacamole into an
- existing application would be similar.</para>
- </section>
-</chapter>
diff --git a/src/conf.py b/src/conf.py
new file mode 100644
index 0000000..154ce65
--- /dev/null
+++ b/src/conf.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from datetime import date
+import os, sys
+
+#
+# Project, version, and author information
+#
+
+project = u'Apache Guacamole'
+version = u'1.3.0'
+
+year = date.today().year
+author = u'The Apache Software Foundation'
+copyright = u'%s %s' % (year, author)
+
+# Include "ext" directory in search path for custom Sphinx extensions
+sys.path.insert(0, os.path.abspath('ext'))
+
+#
+# Global options
+#
+
+extensions = [
+ 'guac',
+ 'myst_parser',
+ 'sphinx.ext.ifconfig',
+ 'sphinx.ext.extlinks',
+ 'sphinx_inline_tabs'
+]
+
+# Allow shorthand notation for JIRA issue links
+extlinks = {
+ 'jira': ( 'https://issues.apache.org/jira/browse/%s', '')
+}
+
+templates_path = [ '_templates' ]
+
+# Do not highlight source unless a Pygments lexer name is explicitly provided
+highlight_language = 'none'
+
+myst_enable_extensions = [
+ "colon_fence",
+ "deflist",
+ "replacements",
+ "smartquotes",
+ "substitution"
+]
+
+myst_substitutions = {
+ "version" : version
+}
+
+#
+# HTML output options
+#
+
+html_theme = 'sphinx_rtd_theme'
+html_title = u'Apache Guacamole Manual v%s' % version
+
+html_static_path = [ '_static' ]
+html_css_files = [ 'gug.css' ]
+
+html_context = {
+ 'copyright_year' : year
+}
+
diff --git a/src/configuring-guacamole.md b/src/configuring-guacamole.md
new file mode 100644
index 0000000..ea6099f
--- /dev/null
+++ b/src/configuring-guacamole.md
@@ -0,0 +1,2776 @@
+Configuring Guacamole
+=====================
+
+After installing Guacamole, you need to configure users and connections before
+Guacamole will work. This chapter covers general configuration of Guacamole and
+the use of its default authentication method.
+
+Guacamole's default authentication method reads all users and connections from
+a single file called `user-mapping.xml`. This authentication method is intended
+to be:
+
+1. Sufficient for small deployments of Guacamole.
+
+2. A relatively-easy means of verifying that Guacamole has been properly set
+ up.
+
+Other, more complex authentication methods which use backend databases, LDAP,
+etc. are discussed in a separate, dedicated chapters.
+
+Regardless of the authentication method you use, Guacamole's configuration
+always consists of two main pieces: a directory referred to as
+`GUACAMOLE_HOME`, which is the primary search location for configuration files,
+and `guacamole.properties`, the main configuration file used by Guacamole and
+its extensions.
+
+(guacamole-home)=
+
+`GUACAMOLE_HOME` (`/etc/guacamole`)
+---------------------------------------
+
+`GUACAMOLE_HOME` is the name given to Guacamole's configuration directory,
+which is located at `/etc/guacamole` by default. All configuration files,
+extensions, etc. reside within this directory. The structure of
+`GUACAMOLE_HOME` is rigorously defined, and consists of the following optional
+files:
+
+`guacamole.properties`
+: The main Guacamole configuration file. Properties within this file dictate
+ how Guacamole will connect to guacd, and may configure the behavior of
+ installed authentication extensions.
+
+`logback.xml`
+: Guacamole uses a logging system called Logback for all messages. By
+ default, Guacamole will log to the console only, but you can change this
+ by providing your own Logback configuration file.
+
+`extensions/`
+: The install location for all Guacamole extensions. Guacamole will
+ automatically load all `.jar` files within this directory on startup.
+
+`lib/`
+: The search directory for libraries required by any Guacamole extensions.
+ Guacamole will make the `.jar` files within this directory available to
+ all extensions. If your extensions require additional libraries, such as
+ database drivers, this is the proper place to put them.
+
+(overriding-guacamole-home)=
+
+### Overriding `GUACAMOLE_HOME`
+
+If you cannot or do not wish to use `/etc/guacamole` for `GUACAMOLE_HOME`, the
+location can be overridden through any of the following methods:
+
+1. Creating a directory named `.guacamole`, within the home directory of *the
+ user running the servlet container*. This directory will automatically be
+ used for `GUACAMOLE_HOME` if it exists.
+
+2. Specifying the full path to an alternative directory with the environment
+ variable `GUACAMOLE_HOME`. *Be sure to consult the documentation for your
+ servlet container to determine how to properly set environment variables.*
+
+3. Specifying the full path to an alternative directory with the system
+ property guacamole.home.
+
+(initial-setup)=
+
+`guacamole.properties`
+------------------------
+
+The Guacamole web application uses one main configuration file called
+`guacamole.properties`. This file is the common location for all configuration
+properties read by Guacamole or any extension of Guacamole, including
+authentication providers.
+
+In previous releases, this file had to be in the classpath of your servlet
+container. Now, the location of `guacamole.properties` can be explicitly
+defined with environment variables or system properties, and the classpath is
+only used as a last resort. When searching for `guacamole.properties`,
+Guacamole will check, in order:
+
+1. Within `GUACAMOLE_HOME`, as defined above.
+
+2. The classpath of the servlet container.
+
+The `guacamole.properties` file is optional and is used to configure Guacamole
+in situations where the defaults are insufficient, or to provide additional
+configuration information for extensions. There are several standard properties
+that are always available for use:
+
+`api-session-timeout`
+: The amount of time, in minutes, to allow Guacamole sessions
+ (authentication tokens) to remain valid despite inactivity. If omitted,
+ Guacamole sessions will expire after 60 minutes of inactivity.
+
+`api-max-request-size`
+: The maximum number of bytes to accept within the entity body of any
+ particular HTTP request, where 0 indicates that no limit should be
+ applied. If omitted, requests will be limited to 2097152 bytes (2 MB) by
+ default. This limit does not apply to file uploads.
+
+ If using a reverse proxy for SSL termination, *keep in mind that reverse
+ proxies may enforce their own limits independently of this*. For example,
+ [Nginx will enforce a 1 MB request size limit by
+ default](nginx-file-upload-size).
+
+`allowed-languages`
+: A comma-separated whitelist of language keys to allow as display language
+ choices within the Guacamole interface. For example, to restrict Guacamole
+ to only English and German, you would specify:
+
+ ```
+ allowed-languages: en, de
+ ```
+
+ As English is the fallback language, used whenever a translation key is
+ missing from the chosen language, English should only be omitted from this
+ list if you are absolutely positive that no strings are missing.
+
+ The corresponding JSON of any built-in languages not listed here will
+ still be available over HTTP, but the Guacamole interface will not use
+ them, nor will they be used automatically based on local browser language.
+ If omitted, all defined languages will be available.
+
+`enable-environment-properties`
+: If set to "true", Guacamole will first evaluate its environment to obtain
+ the value for any given configuration property, before using a value
+ specified in `guacamole.properties` or falling back to a default value. By
+ enabling this option, you can easily override any other configuration
+ property using an environment variable.
+
+ ```
+ enable-environment-properties: true
+ ```
+
+ When searching for a configuration property in the environment, the name
+ of the property is first transformed by converting all lower case
+ characters to their upper case equivalents, and by replacing all hyphen
+ characters (`-`) with underscore characters (`_`). For example, the
+ `guacd-hostname` property would be transformed to `GUACD_HOSTNAME` when
+ searching the environment.
+
+`guacd-hostname`
+: The host the Guacamole proxy daemon (guacd) is listening on. If omitted,
+ Guacamole will assume guacd is listening on localhost.
+
+`guacd-port`
+: The port the Guacamole proxy daemon (guacd) is listening on. If omitted,
+ Guacamole will assume guacd is listening on port 4822.
+
+`guacd-ssl`
+: If set to "true", Guacamole will require SSL/TLS encryption between the
+ web application and guacd. By default, communication between the web
+ application and guacd will be unencrypted.
+
+ Note that if you enable this option, you must also configure guacd to use
+ SSL via command line options. These options are documented in the manpage
+ of guacd. You will need an SSL certificate and private key.
+
+`skip-if-unavailable`
+: A comma-separated list of the identifiers of authentication providers that
+ should be allowed to fail internally without aborting the authentication
+ process. For example, to request that Guacamole ignore failures due to the
+ LDAP directory or MySQL server being unexpectedly down, allowing other
+ authentication providers to continue functioning:
+
+ ```
+ skip-if-unavailable: mysql, ldap
+ ```
+
+ By default, Guacamole takes a conservative approach to internal failures,
+ aborting the authentication process if an internal error occurs within any
+ authentication provider. Depending on the nature of the error, this may
+ mean that no users can log in until the cause of the failure is dealt
+ with. The `skip-if-unavailable` property may be used to explicitly inform
+ Guacamole that one or more underlying systems are expected to occasionally
+ experience failures, and that other functioning systems should be relied
+ upon if they do fail.
+
+A typical `guacamole.properties` that defines explicit values for the
+`guacd-hostname` and `guacd-port` properties would look like:
+
+```
+# Hostname and port of guacamole proxy
+guacd-hostname: localhost
+guacd-port: 4822
+```
+
+(webapp-logging)=
+
+Logging within the web application
+----------------------------------
+
+By default, Guacamole logs all messages to the console. Servlet containers like
+Tomcat will automatically redirect these messages to a log file, `catalina.out`
+in the case of Tomcat, which you can read through while Guacamole runs.
+Messages are logged at four different log levels, depending on message
+importance and severity:
+
+`error`
+: Errors are fatal conditions. An operation, described in the log message,
+ was attempted but could not proceed, and the failure of this operation is
+ a serious problem that needs to be addressed.
+
+`warn`
+: Warnings are generally non-fatal conditions. The operation continued, but
+ encountered noteworthy problems.
+
+`info`
+: "Info" messages are purely informational. They may be useful or
+ interesting to administrators, but are not generally critical to proper
+ operation of a Guacamole server.
+
+`debug`
+: Debug messages are highly detailed and oriented toward development. Most
+ debug messages will contain stack traces and internal information that is
+ useful when investigating problems within code. It is expected that debug
+ messages, though verbose, will not affect performance.
+
+`trace`
+: Trace messages are similar to debug messages in intent and verbosity, but
+ are so low-level that they may affect performance due to their frequency.
+ Trace-level logging is rarely necessary, and is mainly useful in providing
+ highly detailed context around issues being investigated.
+
+Guacamole logs messages using a logging framework called
+[Logback](http://logback.qos.ch/) and, by default, will only log messages at
+the "`info`" level or higher. If you wish to change the log level, or configure
+how or where Guacamole logs messages, you can do so by providing your own
+`logback.xml` file within `GUACAMOLE_HOME`. For example, to log all messages
+to the console, even "`debug`" messages, you might use the following
+`logback.xml`:
+
+```xml
+<configuration>
+
+ <!-- Appender for debugging -->
+ <appender name="GUAC-DEBUG" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <!-- Log at DEBUG level -->
+ <root level="debug">
+ <appender-ref ref="GUAC-DEBUG"/>
+ </root>
+
+</configuration>
+```
+
+Guacamole and the above example configure only one appender which logs to the
+console, but Logback is extremely flexible and allows any number of appenders
+which can each log to separate files, the console, etc. based on a number of
+criteria, including the log level and the source of the message.
+
+More thorough [documentation on configuring
+Logback](http://logback.qos.ch/manual/configuration.html) is provided on the
+Logback project's web site.
+
+(basic-auth)=
+
+Using the default authentication
+--------------------------------
+
+Guacamole's default authentication module is simple and consists of a mapping
+of usernames to configurations. This authentication module comes with Guacamole
+and simply reads usernames and passwords from an XML file. It is always
+enabled, but will only read from the XML file if it exists, and is always last
+in priority relative to any other authentication extensions.
+
+There are other authentication modules available. The Guacamole project
+provides database-backed authentication modules with the ability to manage
+connections and users from the web interface, and other authentication modules
+can be created using the extension API provided along with the Guacamole web
+application, guacamole-ext.
+
+(user-mapping)=
+
+### `user-mapping.xml`
+
+The default authentication provider used by Guacamole reads all username,
+password, and configuration information from a file called the "user mapping"
+located at `GUACAMOLE_HOME/user-mapping.xml`. An example of a user mapping file
+is included with Guacamole, and looks something like this:
+
+```xml
+<user-mapping>
+
+ <!-- Per-user authentication and config information -->
+ <authorize username="USERNAME" password="PASSWORD">
+ <protocol>vnc</protocol>
+ <param name="hostname">localhost</param>
+ <param name="port">5900</param>
+ <param name="password">VNCPASS</param>
+ </authorize>
+
+ <!-- Another user, but using md5 to hash the password
+ (example below uses the md5 hash of "PASSWORD") -->
+ <authorize
+ username="USERNAME2"
+ password="319f4d26e3c536b5dd871bb2c52e3178"
+ encoding="md5">
+
+ <!-- First authorized connection -->
+ <connection name="localhost">
+ <protocol>vnc</protocol>
+ <param name="hostname">localhost</param>
+ <param name="port">5901</param>
+ <param name="password">VNCPASS</param>
+ </connection>
+
+ <!-- Second authorized connection -->
+ <connection name="otherhost">
+ <protocol>vnc</protocol>
+ <param name="hostname">otherhost</param>
+ <param name="port">5900</param>
+ <param name="password">VNCPASS</param>
+ </connection>
+
+ </authorize>
+
+</user-mapping>
+```
+
+Each user is specified with a corresponding `<authorize>` tag. This tag
+contains all authorized connections for that user, each denoted with a
+`<connection>` tag. Each `<connection>` tag contains a corresponding protocol
+and set of protocol-specific parameters, specified with the `<protocol>` and
+`<param>` tags respectively.
+
+(user-setup)=
+
+#### Adding users
+
+When using `user-mapping.xml`, username/password pairs are specified with
+`<authorize>` tags, which each have a `username` and `password` attribute. Each
+`<authorize>` tag authorizes a specific username/password pair to access all
+connections within the tag:
+
+```xml
+<authorize username="USER" password="PASS">
+ ...
+</authorize>
+```
+
+In the example above, the password would be listed in plaintext. If you don't
+want to do this, you can also specify your password hashed with MD5:
+
+```xml
+<authorize username="USER"
+ password="319f4d26e3c536b5dd871bb2c52e3178"
+ encoding="md5">
+ ...
+</authorize>
+```
+
+After modifying `user-mapping.xml`, the file will be automatically reread by
+Guacamole, and your changes will take effect immediately. The newly-added user
+will be able to log in - no restart of the servlet container is needed.
+
+(connection-setup)=
+
+#### Adding connections to a user
+
+To specify a connection within an `<authorize>` tag, you can either list a
+single protocol and set of parameters (specified with a `<protocol>` tag and
+any number of `<param>` tags), in which case that user will have access to only
+one connection named "DEFAULT", or you can specify one or more connections with
+one or more `<connection>` tags, each of which can be named and contains a
+`<protocol>` tag and any number of `<param>` tags.
+
+(connection-configuration)=
+
+Configuring connections
+-----------------------
+
+Each protocol supported by Guacamole has its own set of configuration
+parameters. These parameters typically describe the hostname and port of the
+remote desktop server, the credentials to use when connecting, if any, and the
+size and color depth of the display. If the protocol supports file transfer,
+options for enabling that functionality will be provided as well.
+
+### VNC
+
+The VNC protocol is the simplest and first protocol supported by Guacamole.
+Although generally not as fast as RDP, many VNC servers are adequate, and VNC
+over Guacamole tends to be faster than VNC by itself due to decreased bandwidth
+usage.
+
+VNC support for Guacamole is provided by the libguac-client-vnc library, which
+will be installed as part of guacamole-server if the required dependencies are
+present during the build.
+
+:::{note}
+In addition to the VNC-specific parameters below, Guacamole's VNC support also
+accepts the parameters of several features that Guacamole provides for multiple
+protocols:
+
+* [](disable-clipboard)
+* [](common-sftp)
+* [](graphical-recording)
+* [](wake-on-lan)
+:::
+
+(vnc-network-parameters)=
+
+#### Network parameters
+
+With the exception of reverse-mode VNC connections, VNC works by making
+outbound network connections to a particular host which runs one or more VNC
+servers. Each VNC server is associated with a display number, from which the
+appropriate port number is derived.
+
+`hostname`
+: The hostname or IP address of the VNC server Guacamole should connect to.
+
+`port`
+: The port the VNC server is listening on, usually 5900 or 5900 + display
+ number. For example, if your VNC server is serving display number 1
+ (sometimes written as `:1`), your port number here would be 5901.
+
+`autoretry`
+: The number of times to retry connecting before giving up and returning an
+ error. In the case of a reverse connection, this is the number of times
+ the connection process is allowed to time out.
+
+(vnc-authentication)=
+
+#### Authentication
+
+The VNC standard defines only password based authentication. Other
+authentication mechanisms exist, but are non-standard or proprietary.
+Guacamole currently supports both standard password-only based authentication,
+as well as username and password authentication.
+
+`username`
+: The username to use when attempting authentication, if any. This parameter
+ is optional.
+
+`password`
+: The password to use when attempting authentication, if any. This parameter
+ is optional.
+
+(vnc-display-settings)=
+
+#### Display settings
+
+VNC servers do not allow the client to request particular display sizes, so you
+are at the mercy of your VNC server with respect to display width and height.
+However, to reduce bandwidth usage, you may request that the VNC server reduce
+its color depth. Guacamole will automatically detect 256-color images, but this
+can be guaranteed for absolutely all graphics sent over the connection by
+forcing the color depth to 8-bit. Color depth is otherwise dictated by the VNC
+server.
+
+If you are noticing problems with your VNC display, such as the lack of a mouse
+cursor, the presence of multiple mouse cursors, or strange colors (such as blue
+colors appearing more like orange or red), these are typically the result of
+bugs or limitations within the VNC server, and additional parameters are
+available to work around such issues.
+
+`color-depth`
+: The color depth to request, in bits-per-pixel. This parameter is optional.
+ If specified, this must be either 8, 16, 24, or 32. Regardless of what
+ value is chosen here, if a particular update uses less than 256 colors,
+ Guacamole will always send that update as a 256-color PNG.
+
+`swap-red-blue`
+: If the colors of your display appear wrong (blues appear orange or red,
+ etc.), it may be that your VNC server is sending image data incorrectly,
+ and the red and blue components of each color are swapped. If this is the
+ case, set this parameter to "true" to work around the problem. This
+ parameter is optional.
+
+`cursor`
+: If set to "remote", the mouse pointer will be rendered remotely, and the
+ local position of the mouse pointer will be indicated by a small dot. A
+ remote mouse cursor will feel slower than a local cursor, but may be
+ necessary if the VNC server does not support sending the cursor image to
+ the client.
+
+`encodings`
+: A space-delimited list of VNC encodings to use. The format of this
+ parameter is dictated by libvncclient and thus doesn't really follow the
+ form of other Guacamole parameters. This parameter is optional, and
+ libguac-client-vnc will use any supported encoding by default.
+
+ Beware that this parameter is intended to be replaced with individual,
+ encoding-specific parameters in a future release.
+
+`read-only`
+: Whether this connection should be read-only. If set to "true", no input
+ will be accepted on the connection at all. Users will only see the desktop
+ and whatever other users using that same desktop are doing. This parameter
+ is optional.
+
+`force-lossless`
+: Whether this connection should only use lossless compression for graphical
+ updates. If set to "true", lossy compression will not be used. This
+ parameter is optional. By default, lossy compression will be used when
+ heuristics determine that it would likely outperform lossless compression.
+
+#### VNC Repeater
+
+There exist VNC repeaters, such as UltraVNC Repeater, which act as
+intermediaries or proxies, providing a single logical VNC connection which is
+then routed to another VNC server elsewhere. Additional parameters are required
+to select which VNC host behind the repeater will receive the connection.
+
+`dest-host`
+: The destination host to request when connecting to a VNC proxy such as
+ UltraVNC Repeater. This is only necessary if the VNC proxy in use requires
+ the connecting user to specify which VNC server to connect to. If the VNC
+ proxy automatically connects to a specific server, this parameter is not
+ necessary.
+
+`dest-port`
+: The destination port to request when connecting to a VNC proxy such as
+ UltraVNC Repeater. This is only necessary if the VNC proxy in use requires
+ the connecting user to specify which VNC server to connect to. If the VNC
+ proxy automatically connects to a specific server, this parameter is not
+ necessary.
+
+(vnc-reverse-connections)=
+
+#### Reverse VNC connections
+
+Guacamole supports "reverse" VNC connections, where the VNC client listens for
+an incoming connection from the VNC server. When reverse VNC connections are
+used, the VNC client and server switch network roles, but otherwise function as
+they normally would. The VNC server still provides the remote display, and the
+VNC client still provides all keyboard and mouse input.
+
+`reverse-connect`
+: Whether reverse connection should be used. If set to "true", instead of
+ connecting to a server at a given hostname and port, guacd will listen on
+ the given port for inbound connections from a VNC server.
+
+`listen-timeout`
+: If reverse connection is in use, the maximum amount of time to wait for an
+ inbound connection from a VNC server, in milliseconds. If blank, the
+ default value is 5000 (five seconds).
+
+(vnc-audio)=
+
+#### Audio support (via PulseAudio)
+
+VNC does not provide its own support for audio, but Guacamole's VNC support can
+obtain audio through a secondary network connection to a PulseAudio server
+running on the same machine as the VNC server.
+
+Most Linux systems provide audio through a service called PulseAudio. This
+service is capable of communicating over the network, and if PulseAudio is
+configured to allow TCP connections, Guacamole can connect to your PulseAudio
+server and combine its audio with the graphics coming over VNC.
+
+Configuring PulseAudio for network connections requires an additional line
+within the PulseAudio configuration file, usually `/etc/pulse/default.pa`:
+
+```
+load-module module-native-protocol-tcp auth-ip-acl=192.168.1.0/24 auth-anonymous=1
+```
+
+This loads the TCP module for PulseAudio, configuring it to accept connections
+without authentication and *only* from the `192.168.1.0/24` subnet. You will
+want to replace this value with the subnet or IP address from which guacd will
+be connecting. It is possible to allow connections from absolutely anywhere,
+but beware that you should only do so if the nature of your network prevents
+unauthorized access:
+
+```
+load-module module-native-protocol-tcp auth-anonymous=1
+```
+
+In either case, the `auth-anonymous=1` parameter is strictly required.
+Guacamole does not currently support the cookie-based authentication used by
+PulseAudio for non-anonymous connections. If this parameter is omitted,
+Guacamole will not be able to connect to PulseAudio.
+
+Once the PulseAudio configuration file has been modified appropriately, restart
+the PulseAudio service. PulseAudio should then begin listening on port 4713
+(the default PulseAudio port) for incoming TCP connections. You can verify this
+using a utility like {command}`netstat`:
+
+```console
+$ netstat -ln | grep 4713
+tcp 0 0 0.0.0.0:4713 0.0.0.0:* LISTEN
+tcp6 0 0 :::4713 :::* LISTEN
+$
+```
+
+The following parameters are available for configuring the audio support for
+VNC:
+
+`enable-audio`
+: If set to "true", audio support will be enabled, and a second connection
+ for PulseAudio will be made in addition to the VNC connection. By default,
+ audio support within VNC is disabled.
+
+`audio-servername`
+: The name of the PulseAudio server to connect to. This will be the hostname
+ of the computer providing audio for your connection via PulseAudio, most
+ likely the same as the value given for the `hostname` parameter.
+
+ If this parameter is omitted, the default PulseAudio device will be used,
+ which will be the PulseAudio server running on the same machine as guacd.
+
+(vnc-clipboard-encoding)=
+
+#### Clipboard encoding
+
+While Guacamole will always use UTF-8 for its own clipboard data, the VNC
+standard requires that clipboard data be encoded in ISO 8859-1. As most VNC
+servers will not accept data in any other format, Guacamole will translate
+between UTF-8 and ISO 8859-1 when exchanging clipboard data with the VNC
+server, but this behavior can be overridden with the `clipboard-encoding`
+parameter.
+
+:::{important}
+*The only clipboard encoding guaranteed to be supported by VNC servers is ISO
+8859-1.* You should only override the clipboard encoding using the
+`clipboard-encoding` parameter of you are absolutely positive your VNC server
+supports other encodings.
+:::
+
+`clipboard-encoding`
+: The encoding to assume for the VNC clipboard. This parameter is optional.
+ By default, the standard encoding ISO 8859-1 will be used. *Only use this
+ parameter if you are sure your VNC server supports other encodings beyond
+ the standard ISO 8859-1.*
+
+ Possible values are:
+
+ ISO8859-1
+ : ISO 8859-1 is the clipboard encoding mandated by the VNC standard, and
+ supports only basic Latin characters. Unless your VNC server specifies
+ otherwise, this encoding is the only encoding guaranteed to work.
+
+ UTF-8
+ : UTF-8 - the most common encoding used for Unicode. Using this encoding
+ for the VNC clipboard violates the VNC specification, but some servers
+ do support this. This parameter value should only be used if you know
+ your VNC server supports this encoding.
+
+ UTF-16
+ : UTF-16 - a 16-bit encoding for Unicode which is not as common as UTF-8,
+ but still widely used. Using this encoding for the VNC clipboard
+ violates the VNC specification. This parameter value should only be used
+ if you know your VNC server supports this encoding.
+
+ CP1252
+ : Code page 1252 - a Windows-specific encoding for Latin characters which
+ is mostly a superset of ISO 8859-1, mapping some additional displayable
+ characters onto what would otherwise be control characters. Using this
+ encoding for the VNC clipboard violates the VNC specification. This
+ parameter value should only be used if you know your VNC server supports
+ this encoding.
+
+(adding-vnc)=
+
+#### Adding a VNC connection
+
+If you are using the default authentication built into Guacamole, and you wish
+to grant access to a VNC connection to a particular user, you need to locate
+the `<authorize>` section for that user within your `user-mapping.xml`, and add
+a section like the following within it:
+
+```xml
+<connection name="Unique Name">
+ <protocol>vnc</protocol>
+ <param name="hostname">localhost</param>
+ <param name="port">5901</param>
+</connection>
+```
+
+If added exactly as above, a new connection named "`Unique Name`" will be
+available to the user associated with the `<authorize>` section containing it.
+The connection will use VNC to connect to localhost at port 5901. Naturally,
+you will want to change some or all of these values.
+
+If your VNC server requires a password, or you wish to specify other
+configuration parameters (to reduce the color depth, for example), you will
+need to add additional `<param>` tags accordingly.
+
+Other authentication methods will provide documentation describing how to
+configure new connections. If the authentication method in use fully implements
+the features of Guacamole's authentication API, you will be able to add a new
+VNC connection easily and intuitively using the administration interface built
+into Guacamole. You will not need to edit configuration files.
+
+(vnc-servers)=
+
+#### Which VNC server?
+
+The choice of VNC server can make a big difference when it comes to
+performance, especially over slower networks. While many systems provide VNC
+access by default, using this is often not the fastest method.
+
+(realvnc)=
+
+##### RealVNC or TigerVNC
+
+RealVNC, and its derivative TigerVNC, perform quite well. In our testing, they
+perform the best with Guacamole. If you are okay with having a desktop that can
+only be accessed via VNC, one of these is likely your best choice. Both
+optimize window movement and (depending on the application) scrolling, giving a
+very responsive user experience.
+
+##### TightVNC
+
+TightVNC is widely-available and performs generally as well as RealVNC or
+TigerVNC. If you wish to use TightVNC with Guacamole, performance should be
+just fine, but we highly recommend disabling its JPEG encoding. This is because
+images transmitted to Guacamole are always encoded losslessly as PNG images.
+When this operation is performed on a JPEG image, the artifacts present from
+JPEG's lossy compression reduce the compressibility of the image for PNG, thus
+leading to a slower experience overall than if JPEG was simply not used to
+begin with.
+
+##### x11vnc
+
+The main benefit of using x11vnc is that it allows you to continue using your
+desktop normally, while simultaneously exposing control of your desktop via
+VNC. Performance of x11vnc is comparable to RealVNC, TigerVNC, and TightVNC. If
+you need to use your desktop locally as well as via VNC, you will likely be
+quite happy with x11vnc.
+
+##### vino
+
+vino is the VNC server that comes with the Gnome desktop environment, and is
+enabled if you enable "desktop sharing" via the system preferences available
+within Gnome. If you need to share your local desktop, we recommend using
+x11vnc rather vino, as it has proven more performant and feature-complete in
+our testing. If you don't need to share a local desktop but simply need an
+environment you can access remotely, using a VNC server like RealVNC, TigerVNC,
+or TightVNC is a better choice.
+
+(qemu)=
+
+##### QEMU or KVM
+
+QEMU (and thus KVM) expose the displays of virtual machines using VNC. If you
+need to see the virtual monitor of your virtual machine, using this VNC
+connection is really your only choice. As the VNC server built into QEMU cannot
+be aware of higher-level operations like window movement, resizing, or
+scrolling, those operations will tend to be sent suboptimally, and will not be
+as fast as a VNC server running within the virtual machine.
+
+If you wish to use a virtual machine for desktop access, we recommend
+installing a native VNC server inside the virtual machine after the virtual
+machine is set up. This will give a more responsive desktop.
+
+### RDP
+
+The RDP protocol is more complicated than VNC and was the second protocol
+officially supported by Guacamole. RDP tends to be faster than VNC due to the
+use of caching, which Guacamole does take advantage of.
+
+RDP support for Guacamole is provided by the libguac-client-rdp library, which
+will be installed as part of guacamole-server if the required dependencies are
+present during the build.
+
+:::{note}
+In addition to the RDP-specific parameters below, Guacamole's RDP support also
+accepts the parameters of several features that Guacamole provides for multiple
+protocols:
+
+* [](disable-clipboard)
+* [](common-sftp)
+* [](graphical-recording)
+* [](wake-on-lan)
+:::
+
+(rdp-network-parameters)=
+
+#### Network parameters
+
+RDP connections require a hostname or IP address defining the
+destination machine. The RDP port is defined to be 3389, and will be
+this value in most cases. You only need to specify the RDP port if you
+are not using port 3389.
+
+`hostname`
+: The hostname or IP address of the RDP server Guacamole should connect to.
+
+`port`
+: The port the RDP server is listening on. This parameter is optional. If
+ this is not specified, the standard port for RDP (3389) or Hyper-V's
+ default port for VMConnect (2179) will be used, depending on the security
+ mode selected.
+
+(rdp-authentication)=
+
+#### Authentication and security
+
+RDP provides authentication through the use of a username, password, and
+optional domain. All RDP connections are encrypted.
+
+Most RDP servers will provide a graphical login if the username, password, and
+domain parameters are omitted. One notable exception to this is Network Level
+Authentication, or NLA, which performs all authentication outside of a desktop
+session, and thus in the absence of a graphical interface.
+
+Servers that require NLA can be handled by Guacamole in one of two ways. The
+first is to provide the username and password within the connection
+configuration, either via static values or by passing through the Guacamole
+credentials with [parameter tokens](parameter-tokens) and [](ldap-auth).
+Alternatively, if credentials are not configured within the connection
+configuration, Guacamole will attempt to prompt the user for the credentials
+interactively, if the versions of both guacd and Guacamole Client in use
+support it. If either component does not support prompting and the credentials
+are not configured, NLA-based connections will fail.
+
+`username`
+: The username to use to authenticate, if any. This parameter is optional.
+
+`password`
+: The password to use when attempting authentication, if any. This parameter
+ is optional.
+
+`domain`
+: The domain to use when attempting authentication, if any. This parameter
+ is optional.
+
+`security`
+: The security mode to use for the RDP connection. This mode dictates how
+ data will be encrypted and what type of authentication will be performed,
+ if any. By default, a security mode is selected based on a negotiation
+ process which determines what both the client and the server support.
+
+ Possible values are:
+
+ any
+ : Automatically select the security mode based on the security protocols
+ supported by both the client and the server. *This is the default*.
+
+ nla
+ : Network Level Authentication, sometimes also referred to as "hybrid" or
+ CredSSP (the protocol that drives NLA). This mode uses TLS encryption
+ and requires the username and password to be given in advance. Unlike
+ RDP mode, the authentication step is performed before the remote desktop
+ session actually starts, avoiding the need for the Windows server to
+ allocate significant resources for users that may not be authorized.
+
+ If the versions of guacd and Guacamole Client in use support prompting
+ and the username, password, and domain are not specified, the user will
+ be interactively prompted to enter credentials to complete NLA and
+ continue the connection. Otherwise, when prompting is not supported and
+ credentials are not provided, NLA connections will fail.
+
+ nla-ext
+ : Extended Network Level Authentication. This mode is identical to NLA
+ except that an additional "[Early User Authorization
+ Result](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/d0e560a3-25cb-4563-8bdc-6c4cc625bbfc)"
+ is required to be sent from the server to the client immediately after the
+ NLA handshake is completed.
+
+ tls
+ : RDP authentication and encryption implemented via TLS (Transport Layer
+ Security). Also referred to as RDSTLS, the TLS security mode is
+ primarily used in load balanced configurations where the initial RDP
+ server may redirect the connection to a different RDP server.
+
+ vmconnect
+ : Automatically select the security mode based on the security protocols
+ supported by both the client and the server, limiting that negotiation
+ to only the protocols known to be supported by [Hyper-V /
+ VMConnect](rdp-preconnection-pdu).
+
+ rdp
+ : Legacy RDP encryption. This mode is generally only used for older
+ Windows servers or in cases where a standard Windows login screen is
+ desired. Newer versions of Windows have this mode disabled by default
+ and will only accept NLA unless explicitly configured otherwise.
+
+`ignore-cert`
+: If set to "true", the certificate returned by the server will be ignored,
+ even if that certificate cannot be validated. This is useful if you
+ universally trust the server and your connection to the server, and you
+ know that the server's certificate cannot be validated (for example, if it
+ is self-signed).
+
+`disable-auth`
+: If set to "true", authentication will be disabled. Note that this refers
+ to authentication that takes place while connecting. Any authentication
+ enforced by the server over the remote desktop session (such as a login
+ dialog) will still take place. By default, authentication is enabled and
+ only used when requested by the server.
+
+ If you are using NLA, authentication must be enabled by definition.
+
+(rdp-session-settings)=
+
+#### Session settings
+
+RDP sessions will typically involve the full desktop environment of a normal
+user. Alternatively, you can manually specify a program to use instead of the
+RDP server's default shell, or connect to the administrative console.
+
+Although Guacamole is independent of keyboard layout, RDP is not. This is
+because Guacamole represents keys based on what they *do* ("press the Enter
+key"), while RDP uses identifiers based on the key's location ("press the
+rightmost key in the second row"). To translate between a Guacamole key event
+and an RDP key event, Guacamole must know ahead of time the keyboard layout of
+the RDP server.
+
+By default, the US English qwerty keyboard will be used. If this does not match
+the keyboard layout of your RDP server, keys will not be properly translated,
+and you will need to explicitly choose a different layout in your connection
+settings. If your keyboard layout is not supported, please notify the Guacamole
+team by [opening an issue in
+JIRA](https://issues.apache.org/jira/browse/GUACAMOLE).
+
+
+`client-name`
+: When connecting to the RDP server, Guacamole will normally provide its own
+ hostname as the name of the client. If this parameter is specified,
+ Guacamole will use its value instead.
+
+ On Windows RDP servers, this value is exposed within the session as the
+ `CLIENTNAME` environment variable.
+
+`console`
+: If set to "true", you will be connected to the console (admin) session of
+ the RDP server.
+
+`initial-program`
+: The full path to the program to run immediately upon connecting. This
+ parameter is optional.
+
+`server-layout`
+: The server-side keyboard layout. This is the layout of the RDP server and
+ has nothing to do with the keyboard layout in use on the client. *The
+ Guacamole client is independent of keyboard layout.* The RDP protocol,
+ however, is *not* independent of keyboard layout, and Guacamole needs to
+ know the keyboard layout of the server in order to send the proper keys
+ when a user is typing.
+
+ Possible values are generally in the format
+ {samp}`{LANGUAGE}-{REGION}-{VARIANT}`, where `LANGUAGE` is the standard
+ two-letter language code for the primary language associated with the
+ layout, `REGION` is a standard representation of the location that the
+ keyboard is used (the two-letter country code, when possible), and
+ `VARIANT` is the specific keyboard layout variant (such as "qwerty",
+ "qwertz", or "azerty"):
+
+ | Keyboard layout | Parameter value |
+ | ------------------------------ | ---------------------- |
+ | Brazilian (Portuguese) | `pt-br-qwerty` |
+ | English (UK) | `en-gb-qwerty` |
+ | English (US) | `en-us-qwerty` |
+ | French | `fr-fr-azerty` |
+ | French (Belgian) | `fr-be-azerty` |
+ | French (Swiss) | `fr-ch-qwertz` |
+ | German | `de-de-qwertz` |
+ | German (Swiss) | `de-ch-qwertz` |
+ | Hungarian | `hu-hu-qwertz` |
+ | Italian | `it-it-qwerty` |
+ | Japanese | `ja-jp-qwerty` |
+ | Spanish | `es-es-qwerty` |
+ | Spanish (Latin American) | `es-latam-qwerty` |
+ | Swedish | `sv-se-qwerty` |
+ | Turkish-Q | `tr-tr-qwerty` |
+
+ If you server's keyboard layout is not yet supported, and it is not possible
+ to set your server to use a supported layout, the `failsafe` layout may be used
+ to force Unicode events to be used for all input, however beware that doing so
+ may prevent keyboard shortcuts from working as expected.
+
+`timezone`
+: The timezone that the client should send to the server for configuring the
+ local time display of that server. The format of the timezone is in the
+ standard IANA key zone format, which is the format used in UNIX/Linux.
+ This will be converted by RDP into the correct format for Windows.
+
+ The timezone is detected and will be passed to the server during the
+ handshake phase of the connection, and may used by protocols, like RDP,
+ that support it. This parameter can be used to override the value detected
+ and passed during the handshake, or can be used in situations where guacd
+ does not support passing the timezone parameter during the handshake phase
+ (guacd versions prior to 1.3.0).
+
+ Support for forwarding the client timezone varies by RDP server
+ implementation. For example, with Windows, support for forwarding
+ timezones is only present in Windows Server with Remote Desktop Services
+ (RDS, formerly known as Terminal Services) installed. Windows Server
+ installations in admin mode, along with Windows workstation versions, do
+ not allow the timezone to be forwarded. Other server implementations, for
+ example, xrdp, may not implement this feature at all. Consult the
+ documentation for the RDP server to determine whether or not this feature
+ is supported.
+
+(rdp-display-settings)=
+
+#### Display settings
+
+Guacamole will automatically choose an appropriate display size for RDP
+connections based on the size of the browser window and the DPI of the device.
+The size of the display can be forced by specifying explicit width or height
+values.
+
+To reduce bandwidth usage, you may also request that the server reduce its
+color depth. Guacamole will automatically detect 256-color images, but this can
+be guaranteed for absolutely all graphics sent over the connection by forcing
+the color depth to 8-bit. Color depth is otherwise dictated by the RDP server.
+
+`color-depth`
+: The color depth to request, in bits-per-pixel. This parameter is optional.
+ If specified, this must be either 8, 16, or 24. Regardless of what value
+ is chosen here, if a particular update uses less than 256 colors,
+ Guacamole will always send that update as a 256-color PNG.
+
+`width`
+: The width of the display to request, in pixels. This parameter is
+ optional. If this value is not specified, the width of the connecting
+ client display will be used instead.
+
+`height`
+: The height of the display to request, in pixels. This parameter is
+ optional. If this value is not specified, the height of the connecting
+ client display will be used instead.
+
+`dpi`
+: The desired effective resolution of the client display, in DPI. This
+ parameter is optional. If this value is not specified, the resolution and
+ size of the client display will be used together to determine,
+ heuristically, an appropriate resolution for the RDP session.
+
+`resize-method`
+: The method to use to update the RDP server when the width or height of the
+ client display changes. This parameter is optional. If this value is not
+ specified, no action will be taken when the client display changes size.
+
+ Normally, the display size of an RDP session is constant and can only be
+ changed when initially connecting. As of RDP 8.1, the "Display Update"
+ channel can be used to request that the server change the display size.
+ For older RDP servers, the only option is to disconnect and reconnect with
+ the new size.
+
+ Possible values are:
+
+ display-update
+ : Uses the "Display Update" channel added with RDP 8.1 to signal the
+ server when the client display size has changed.
+
+ reconnect
+ : Automatically disconnects the RDP session when the client display size
+ has changed, and reconnects with the new size.
+
+`force-lossless`
+: Whether this connection should only use lossless compression for graphical
+ updates. If set to "true", lossy compression will not be used. This
+ parameter is optional. By default, lossy compression will be used when
+ heuristics determine that it would likely outperform lossless compression.
+
+(rdp-device-redirection)=
+
+#### Device redirection
+
+Device redirection refers to the use of non-display devices over RDP.
+Guacamole's RDP support currently allows redirection of audio, printing, and
+disk access, some of which require additional configuration in order to
+function properly.
+
+Audio redirection will be enabled by default. If Guacamole was correctly
+installed, and audio redirection is supported by your RDP server, sound should
+play within remote connections without manual intervention.
+
+Printing requires GhostScript to be installed on the Guacamole server, and
+allows users to print arbitrary documents directly to PDF. When documents are
+printed to the redirected printer, the user will receive a PDF of that document
+within their web browser.
+
+Guacamole provides support for file transfer over RDP by emulating a virtual
+disk drive. This drive will persist on the Guacamole server, confined within
+the drive path specified. If drive redirection is enabled on a Guacamole RDP
+connection, users will be able to upload and download files as described in
+[](using-guacamole).
+
+`disable-audio`
+: Audio is enabled by default in both the client and in libguac-client-rdp.
+ If you are concerned about bandwidth usage, or sound is causing problems,
+ you can explicitly disable sound by setting this parameter to "true".
+
+`enable-audio-input`
+: If set to "true", audio input support (microphone) will be enabled,
+ leveraging the standard "`AUDIO_INPUT`" channel of RDP. By default, audio
+ input support within RDP is disabled.
+
+`enable-printing`
+: Printing is disabled by default, but with printing enabled, RDP users can
+ print to a virtual printer that sends a PDF containing the document
+ printed to the Guacamole client. Enable printing by setting this parameter
+ to "true".
+
+ *Printing support requires GhostScript to be installed.* If guacd cannot
+ find the `gs` executable when printing, the print attempt will fail.
+
+`printer-name`
+: The name of the redirected printer device that is passed through to the
+ RDP session. This is the name that the user will see in, for example, the
+ Devices and Printers control panel.
+
+ If printer redirection is not enabled, this option has no effect.
+
+`enable-drive`
+: File transfer is disabled by default, but with file transfer enabled, RDP
+ users can transfer files to and from a virtual drive which persists on the
+ Guacamole server. Enable file transfer support by setting this parameter
+ to "true".
+
+ Files will be stored in the directory specified by the "`drive-path`"
+ parameter, which is required if file transfer is enabled.
+
+`disable-download`
+: If set to true downloads from the remote server to client (browser) will
+ be disabled. This includes both downloads done via the hidden Guacamole
+ menu, as well as using the special "Download" folder presented to the
+ remote server. The default is false, which means that downloads will be
+ allowed.
+
+ If file transfer is not enabled, this parameter is ignored.
+
+`disable-upload`
+: If set to true, uploads from the client (browser) to the remote server
+ location will be disabled. The default is false, which means uploads will
+ be allowed if file transfer is enabled.
+
+ If file transfer is not enabled, this parameter is ignored.
+
+`drive-name`
+: The name of the filesystem used when passed through to the RDP session.
+ This is the name that users will see in their Computer/My Computer area
+ along with client name (for example, "Guacamole on Guacamole RDP"), and is
+ also the name of the share when accessing the special `\\tsclient` network
+ location.
+
+ If file transfer is not enabled, this parameter is ignored.
+
+`drive-path`
+: The directory on the Guacamole server in which transferred files should be
+ stored. This directory must be accessible by guacd and both readable and
+ writable by the user that runs guacd. *This parameter does not refer to a
+ directory on the RDP server.*
+
+ If file transfer is not enabled, this parameter is ignored.
+
+`create-drive-path`
+: If set to "true", and file transfer is enabled, the directory specified by
+ the `drive-path` parameter will automatically be created if it does not
+ yet exist. Only the final directory in the path will be created - if other
+ directories earlier in the path do not exist, automatic creation will
+ fail, and an error will be logged.
+
+ By default, the directory specified by the `drive-path` parameter will not
+ automatically be created, and attempts to transfer files to a non-existent
+ directory will be logged as errors.
+
+ If file transfer is not enabled, this parameter is ignored.
+
+`console-audio`
+: If set to "true", audio will be explicitly enabled in the console (admin)
+ session of the RDP server. Setting this option to "true" only makes sense
+ if the `console` parameter is also set to "true".
+
+`static-channels`
+: A comma-separated list of static channel names to open and expose as
+ pipes. If you wish to communicate between an application running on the
+ remote desktop and JavaScript, this is the best way to do it. Guacamole
+ will open an outbound pipe with the name of the static channel. If
+ JavaScript needs to communicate back in the other direction, it should
+ respond by opening another pipe with the same name.
+
+ Guacamole allows any number of static channels to be opened, but protocol
+ restrictions of RDP limit the size of each channel name to 7 characters.
+
+(rdp-preconnection-pdu)=
+
+#### Preconnection PDU (Hyper-V / VMConnect)
+
+Some RDP servers host multiple logical RDP connections behind a single server
+listening on a single TCP port. To select between these logical connections, an
+RDP client must send the "preconnection PDU" - a message which contains values
+that uniquely identify the destination, referred to as the "RDP source". This
+mechanism is defined by the ["Session Selection
+Extension](https://msdn.microsoft.com/en-us/library/cc242359.aspx) for the RDP
+protocol, and is implemented by Microsoft's Hyper-V hypervisor.
+
+If you are using Hyper-V, you will need to specify the ID of the destination
+virtual machine within the `preconnection-blob` parameter. This value can be
+determined using PowerShell:
+
+```ps1con
+PS C:\> Get-VM VirtualMachineName | Select-Object Id
+
+Id
+--
+ed272546-87bd-4db9-acba-e36e1a9ca20a
+
+
+PS C:\>
+```
+
+The preconnection PDU is intentionally generic. While its primary use is as a
+means for selecting virtual machines behind Hyper-V, other RDP servers may use
+it as well. It is up to the RDP server itself to determine whether the
+preconnection ID, BLOB, or both will be used, and what their values mean.
+
+*If you do intend to use Hyper-V, beware that its built-in RDP server requires
+different parameters for authentication and Guacamole's defaults will not
+work.* In most cases, you will need to do the following when connecting to
+Hyper-V:
+
+1. Specify both "`username`" and "`password`" appropriately, and set
+ "`security`" to "`vmconnect`". Selecting the "`vmconnect`" security mode
+ will configure Guacamole to automatically negotiate security modes known to
+ be supported by Hyper-V, and will automatically select Hyper-V's default RDP
+ port (2179).
+
+2. If necessary, set "`ignore-cert`" to "`true`". Hyper-V may use a self-signed
+ certificate.
+
+`preconnection-id`
+: The numeric ID of the RDP source. This is a non-negative integer value
+ dictating which of potentially several logical RDP connections should be
+ used. This parameter is optional, and is only required if the RDP server
+ is documented as requiring it. *If using Hyper-V, this should be left
+ blank.*
+
+`preconnection-blob`
+: An arbitrary string which identifies the RDP source - one of potentially
+ several logical RDP connections hosted by the same RDP server. This
+ parameter is optional, and is only required if the RDP server is
+ documented as requiring it, such as Hyper-V. In all cases, the meaning of
+ this parameter is opaque to the RDP protocol itself and is dictated by the
+ RDP server. *For Hyper-V, this will be the ID of the destination virtual
+ machine.*
+
+(rdp-gateway)=
+
+#### Remote desktop gateway
+
+Microsoft's remote desktop server provides an additional gateway service which
+allows external connections to be forwarded to internal RDP servers which are
+otherwise not accessible. If you will be using Guacamole to connect through
+such a gateway, you will need to provide additional parameters describing the
+connection to that gateway, as well as any required credentials.
+
+`gateway-hostname`
+: The hostname of the remote desktop gateway that should be used as an
+ intermediary for the remote desktop connection. *If omitted, a gateway
+ will not be used.*
+
+`gateway-port`
+: The port of the remote desktop gateway that should be used as an
+ intermediary for the remote desktop connection. By default, this will be
+ "443".
+
+`gateway-username`
+: The username of the user authenticating with the remote desktop gateway,
+ if a gateway is being used. This is not necessarily the same as the user
+ actually using the remote desktop connection.
+
+`gateway-password`
+: The password to provide when authenticating with the remote desktop
+ gateway, if a gateway is being used.
+
+`gateway-domain`
+: The domain of the user authenticating with the remote desktop gateway, if
+ a gateway is being used. This is not necessarily the same domain as the
+ user actually using the remote desktop connection.
+
+(rdp-connection-broker)=
+
+#### Load balancing and RDP connection brokers
+
+If your remote desktop servers are behind a load balancer, sometimes referred
+to as a "connection broker" or "TS session broker", that balancer may require
+additional information during the connection process to determine how the
+incoming connection should be routed. RDP does not dictate the format of this
+information; it is specific to the balancer in use.
+
+If you are using a load balancer and are unsure whether such information is
+required, *you will need to check the documentation for your balancer*. If your
+balancer provides `.rdp` files for convenience, look through the contents of
+those files for a string field called "loadbalanceinfo", as that field is where
+the required information/cookie would be specified.
+
+`load-balance-info`
+: The load balancing information or cookie which should be provided to the
+ connection broker. *If no connection broker is being used, this should be
+ left blank.*
+
+(rdp-perf-flags)=
+
+#### Performance flags
+
+RDP provides several flags which control the availability of features that
+decrease performance and increase bandwidth for the sake of aesthetics, such as
+wallpaper, window theming, menu effects, and smooth fonts. These features are
+all disabled by default within Guacamole such that bandwidth usage is
+minimized, but you can manually re-enable them on a per-connection basis if
+desired.
+
+`enable-wallpaper`
+: If set to "true", enables rendering of the desktop wallpaper. By default,
+ wallpaper will be disabled, such that unnecessary bandwidth need not be
+ spent redrawing the desktop.
+
+`enable-theming`
+: If set to "true", enables use of theming of windows and controls. By
+ default, theming within RDP sessions is disabled.
+
+`enable-font-smoothing`
+: If set to "true", text will be rendered with smooth edges. Text over RDP
+ is rendered with rough edges by default, as this reduces the number of
+ colors used by text, and thus reduces the bandwidth required for the
+ connection.
+
+`enable-full-window-drag`
+: If set to "true", the contents of windows will be displayed as windows are
+ moved. By default, the RDP server will only draw the window border while
+ windows are being dragged.
+
+`enable-desktop-composition`
+: If set to "true", graphical effects such as transparent windows and
+ shadows will be allowed. By default, such effects, if available, are
+ disabled.
+
+`enable-menu-animations`
+: If set to "true", menu open and close animations will be allowed. Menu
+ animations are disabled by default.
+
+`disable-bitmap-caching`
+: In certain situations, particularly with RDP server implementations with
+ known bugs, it is necessary to disable RDP's built-in bitmap caching
+ functionality. This parameter allows that to be controlled in a Guacamole
+ session. If set to "true" the RDP bitmap cache will not be used.
+
+`disable-offscreen-caching`
+: RDP normally maintains caches of regions of the screen that are currently
+ not visible in the client in order to accelerate retrieval of those
+ regions when they come into view. This parameter, when set to "true," will
+ disable caching of those regions. This is usually only useful when dealing
+ with known bugs in RDP server implementations and should remain enabled in
+ most circumstances.
+
+`disable-glyph-caching`
+: In addition to screen regions, RDP maintains caches of frequently used
+ symbols or fonts, collectively known as "glyphs." As with bitmap and
+ offscreen caching, certain known bugs in RDP implementations can cause
+ performance issues with this enabled, and setting this parameter to "true"
+ will disable that glyph caching in the RDP session.
+
+ **Glyph caching is currently universally disabled, regardless of the value of
+ this parameter, as glyph caching support is not considered stable by FreeRDP
+ as of the FreeRDP 2.0.0 release. See: {jira}`GUACAMOLE-1191`.**
+
+(rdp-remoteapp)=
+
+#### RemoteApp
+
+Recent versions of Windows provide a feature called RemoteApp which allows
+individual applications to be used over RDP, without providing access to the
+full desktop environment. If your RDP server has this feature enabled and
+configured, you can configure Guacamole connections to use those individual
+applications.
+
+`remote-app`
+: Specifies the RemoteApp to start on the remote desktop. If supported by
+ your remote desktop server, this application, and only this application,
+ will be visible to the user.
+
+ Windows requires a special notation for the names of remote applications.
+ The names of remote applications must be prefixed with two vertical bars.
+ For example, if you have created a remote application on your server for
+ `notepad.exe` and have assigned it the name "notepad", you would set this
+ parameter to: "`||notepad`".
+
+`remote-app-dir`
+: The working directory, if any, for the remote application. This parameter
+ has no effect if RemoteApp is not in use.
+
+`remote-app-args`
+: The command-line arguments, if any, for the remote application. This
+ parameter has no effect if RemoteApp is not in use.
+
+(adding-rdp)=
+
+#### Adding an RDP connection
+
+If you are using the default authentication built into Guacamole, and you wish
+to grant access to a RDP connection to a particular user, you need to locate
+the `<authorize>` section for that user within your `user-mapping.xml`, and add
+a section like the following within it:
+
+```xml
+<connection name="Unique Name">
+ <protocol>rdp</protocol>
+ <param name="hostname">localhost</param>
+ <param name="port">3389</param>
+</connection>
+```
+
+If added exactly as above, a new connection named "`Unique Name`" will be
+available to the user associated with the `<authorize>` section containing it.
+The connection will use RDP to connect to localhost at port 3389. Naturally,
+you will want to change some or all of these values.
+
+If you want to login automatically rather than receive a login prompt upon
+connecting, you can specify a username and password with additional `<param>`
+tags. Other options are available for controlling the color depth, size of the
+screen, etc.
+
+Other authentication methods will provide documentation describing how to
+configure new connections. If the authentication method in use fully implements
+the features of Guacamole's authentication API, you will be able to add a new
+RDP connection easily and intuitively using the administration interface built
+into Guacamole. You will not need to edit configuration files.
+
+### SSH
+
+Unlike VNC or RDP, SSH is a text protocol. Its implementation in Guacamole is
+actually a combination of a terminal emulator and SSH client, because the SSH
+protocol isn't inherently graphical. Guacamole's SSH support emulates a
+terminal on the server side, and draws the screen of this terminal remotely on
+the client.
+
+SSH support for Guacamole is provided by the libguac-client-ssh library, which
+will be installed as part of guacamole-server if the required dependencies are
+present during the build.
+
+:::{note}
+In addition to the SSH-specific parameters below, Guacamole's SSH support also
+accepts the parameters of several features that Guacamole provides for multiple
+protocols:
+
+* [](disable-clipboard)
+* [](graphical-recording)
+* [](typescripts)
+* [](stdin-pipe)
+* [](terminal-behavior)
+* [](terminal-display-settings)
+* [](wake-on-lan)
+:::
+
+(ssh-host-verification)=
+
+#### SSH Host Verification
+
+By default, Guacamole does not do any verification of host identity before
+establishing SSH connections. While this may be safe for private and trusted
+networks, it is not ideal for large networks with unknown/untrusted systems, or
+for SSH connections that traverse the Internet. The potential exists for
+Man-in-the-Middle (MitM) attacks when connecting to these hosts.
+
+Guacamole includes two methods for verifying SSH (and SFTP) server identity
+that can be used to make sure that the host you are connecting to is a host
+that you know and trust. The first method is by reading a file in
+`GUACAMOLE_HOME` called `ssh_known_hosts`. This file should be in the format of
+a standard OpenSSH `known_hosts` file. If the file is not present, no
+verification is done. If the file is present, it is read in at connection time
+and remote host identities are verified against the keys present in the file.
+
+The second method for verifying host identity is by passing a connection
+parameter that contains an OpenSSH known hosts entry for that specific host.
+The `host-key` parameter is used for SSH connections, while the SFTP
+connections associated with RDP and VNC use the `sftp-host-key` parameter. If
+these parameters are not present on their respective connections no host
+identity verification is performed. If the parameter is present then the
+identity of the remote host is verified against the identity provided in the
+parameter before a connection is established.
+
+(ssh-network-parameters)=
+
+#### Network parameters
+
+SSH connections require a hostname or IP address defining the destination
+machine. SSH is standardized to use port 22 and this will be the proper value
+in most cases. You only need to specify the SSH port if you are not using the
+standard port.
+
+`hostname`
+: The hostname or IP address of the SSH server Guacamole should connect to.
+
+`port`
+: The port the SSH server is listening on, usually 22. This parameter is
+ optional. If this is not specified, the default of 22 will be used.
+
+`host-key`
+: The known hosts entry for the SSH server. This parameter is optional, and,
+ if not provided, no verification of host identity will be done. If the
+ parameter is provided the identity of the server will be checked against
+ the data.
+
+ The format of this parameter is that of a single entry from an OpenSSH
+ `known_hosts` file.
+
+ For more information, please see [](ssh-host-verification).
+
+`server-alive-interval`
+: By default the SSH client does not send keepalive requests to the server.
+ This parameter allows you to configure the the interval in seconds at
+ which the client connection sends keepalive packets to the server. The
+ default is 0, which disables sending the packets. The minimum value is 2.
+
+(ssh-authentication)=
+
+#### Authentication
+
+SSH provides authentication through passwords and public key authentication,
+and also supports the "NONE" method.
+
+SSH "NONE" authentication is seen occasionally in appliances and items like
+network or SAN fabric switches. Generally for this authentication method you
+need only provide a username.
+
+For Guacamole to use public key authentication, it must have access to your
+private key and, if applicable, its passphrase. If the private key requires a
+passphrase, but no passphrase is provided, you will be prompted for the
+passphrase upon connecting.
+
+If no private key is provided, Guacamole will attempt to authenticate using a
+password, reading that password from the connection parameters, if provided, or
+by prompting the user directly.
+
+`username`
+: The username to use to authenticate, if any. This parameter is optional.
+ If not specified, you will be prompted for the username upon connecting.
+
+`password`
+: The password to use when attempting authentication, if any. This parameter
+ is optional. If not specified, you will be prompted for your password upon
+ connecting.
+
+`private-key`
+: The entire contents of the private key to use for public key
+ authentication. If this parameter is not specified, public key
+ authentication will not be used. The private key must be in OpenSSH
+ format, as would be generated by the OpenSSH {command}`ssh-keygen`
+ utility.
+
+`passphrase`
+: The passphrase to use to decrypt the private key for use in public key
+ authentication. This parameter is not needed if the private key does not
+ require a passphrase. If the private key requires a passphrase, but this
+ parameter is not provided, the user will be prompted for the passphrase
+ upon connecting.
+
+(ssh-command)=
+
+#### Running a command (instead of a shell)
+
+By default, SSH sessions will start an interactive shell. The shell which will
+be used is determined by the SSH server, normally by reading the user's default
+shell previously set with `chsh` or within `/etc/passwd`. If you wish to
+override this and instead run a specific command, you can do so by specifying
+that command in the configuration of the Guacamole SSH connection.
+
+`command`
+: The command to execute over the SSH session, if any. This parameter is
+ optional. If not specified, the SSH session will use the user's default
+ shell.
+
+#### Internationalization/Locale settings
+
+The language of the session is normally set by the SSH server. If the SSH
+server allows the relevant environment variable to be set, the language can be
+overridden on a per-connection basis.
+
+`locale`
+: The specific locale to request for the SSH session. This parameter is
+ optional and may be any value accepted by the `LANG` environment variable
+ of the SSH server. If not specified, the SSH server's default locale will
+ be used.
+
+ As this parameter is sent to the SSH server using the `LANG` environment
+ variable, the parameter will only have an effect if the SSH server allows
+ the `LANG` environment variable to be set by SSH clients.
+
+`timezone`
+: This parameter allows you to control the timezone that is sent to the
+ server over the SSH connection, which will change the way local time is
+ displayed on the server.
+
+ The mechanism used to do this over SSH connections is by setting the `TZ`
+ variable on the SSH connection to the timezone specified by this
+ parameter. This means that the SSH server must allow the `TZ` variable to
+ be set/overriden - many SSH server implementations have this disabled by
+ default. To get this to work, you may need to modify the configuration of
+ the SSH server and explicitly allow for `TZ` to be set/overriden.
+
+ The available values of this parameter are standard IANA key zone format
+ timezones, and the value will be sent directly to the server in this
+ format.
+
+(ssh-sftp)=
+
+#### SFTP
+
+Guacamole provides support for file transfer over SSH using SFTP, the
+file transfer protocol built into most SSH servers. If SFTP is enabled
+on a Guacamole SSH connection, users will be able to upload and download
+files as described in [](using-guacamole)
+
+`enable-sftp`
+: Whether file transfer should be enabled. If set to "true", the user will
+ be allowed to upload or download files from the SSH server using SFTP.
+ Guacamole includes the {program}`guacctl` utility which controls file
+ downloads and uploads when run on the SSH server by the user over the SSH
+ connection.
+
+`sftp-root-directory`
+: The directory to expose to connected users via Guacamole's [file
+ browser](file-browser). If omitted, the root directory will be used by
+ default.
+
+`sftp-disable-download`
+: If set to true downloads from the remote system to the client (browser)
+ will be disabled. The default is false, which means that downloads will be
+ enabled.
+
+ If SFTP is not enabled, this parameter will be ignored.
+
+`sftp-disable-upload`
+: If set to true uploads from the client (browser) to the remote system will
+ be disabled. The default is false, which means that uploads will be
+ enabled.
+
+ If SFTP is not enabled, this parameter will be ignored.
+
+(adding-ssh)=
+
+#### Adding an SSH connection
+
+If you are using the default authentication built into Guacamole, and
+you wish to grant access to a SSH connection to a particular user, you
+need to locate the `<authorize>` section for that user within your
+`user-mapping.xml`, and add a section like the following within it:
+
+```xml
+<connection name="Unique Name">
+ <protocol>ssh</protocol>
+ <param name="hostname">localhost</param>
+ <param name="port">22</param>
+</connection>
+```
+
+If added exactly as above, a new connection named "`Unique Name`" will be
+available to the user associated with the `<authorize>` section containing it.
+The connection will use SSH to connect to localhost at port 22. Naturally, you
+will want to change some or all of these values.
+
+If you want to login automatically rather than receive a login prompt upon
+connecting, you can specify a username and password with additional `<param>`
+tags. Other options are available for controlling the font.
+
+Other authentication methods will provide documentation describing how to
+configure new connections.
+
+### Telnet
+
+Telnet is a text protocol and provides similar functionality to SSH. By nature,
+it is not encrypted, and does not provide support for file transfer. As far as
+graphics are concerned, Guacamole's telnet support works in the same manner as
+SSH: it emulates a terminal on the server side which renders to the Guacamole
+client's display.
+
+Telnet support for Guacamole is provided by the libguac-client-telnet library,
+which will be installed as part of guacamole-server if the required
+dependencies are present during the build.
+
+:::{note}
+In addition to the telnet-specific parameters below, Guacamole's telnet support
+also accepts the parameters of several features that Guacamole provides for
+multiple protocols:
+
+* [](disable-clipboard)
+* [](graphical-recording)
+* [](typescripts)
+* [](stdin-pipe)
+* [](terminal-behavior)
+* [](terminal-display-settings)
+* [](wake-on-lan)
+:::
+
+(telnet-network-parameters)=
+
+#### Network parameters
+
+Telnet connections require a hostname or IP address defining the
+destination machine. Telnet is standardized to use port 23 and this will
+be the proper value in most cases. You only need to specify the telnet
+port if you are not using the standard port.
+
+`hostname`
+: The hostname or IP address of the telnet server Guacamole should connect
+ to.
+
+`port`
+: The port the telnet server is listening on, usually 23. This parameter is
+ optional. If this is not specified, the default of 23 will be used.
+
+(telnet-authentication)=
+
+#### Authentication
+
+Telnet does not actually provide any standard means of authentication.
+Authentication over telnet depends entirely on the login process running on the
+server and is interactive. To cope with this, Guacamole provides non-standard
+mechanisms for automatically passing the username and entering password.
+Whether these mechanisms work depends on specific login process used by your
+telnet server.
+
+The de-facto method for passing the username automatically via telnet is to
+submit it via the `USER` environment variable, sent using the NEW-ENVIRON
+option. This is the mechanism used by most telnet clients, typically via the
+`-l` command-line option.
+
+Passwords cannot typically be sent automatically - at least not as reliably as
+the username. There is no `PASSWORD` environment variable (this would actually
+be a horrible idea) nor any similar mechanism for passing the password to the
+telnet login process, and most telnet clients provide no built-in support for
+automatically entering the password. The best that can be done is to
+heuristically detect the password prompt, and type the password on behalf of
+the user when the prompt appears. The prescribed method for doing this with a
+traditional command-line telnet is to use a utility like `expect`. Guacamole
+provides similar functionality by searching for the password prompt with a
+regular expression.
+
+If Guacamole receives a line of text which matches the regular expression, the
+password is automatically sent. If no such line is ever received, the password
+is not sent, and the user must type the password manually. Pressing any key
+during this process cancels the heuristic password prompt detection.
+
+If the password prompt is not being detected properly, you can try using your
+own regular expression by specifying it within the `password-regex` parameter.
+The regular expression must be written in the POSIX ERE dialect (the dialect
+typically used by `egrep`).
+
+`username`
+: The username to use to authenticate, if any. This parameter is optional.
+ If not specified, or not supported by the telnet server, the login process
+ on the telnet server will prompt you for your credentials. For this to
+ work, your telnet server must support the NEW-ENVIRON option, and the
+ telnet login process must pay attention to the `USER` environment
+ variable. Most telnet servers satisfy this criteria.
+
+`password`
+: The password to use when attempting authentication, if any. This parameter
+ is optional. If specified, your password will be typed on your behalf when
+ the password prompt is detected.
+
+`username-regex`
+: The regular expression to use when waiting for the username prompt. This
+ parameter is optional. If not specified, a reasonable default built into
+ Guacamole will be used. The regular expression must be written in the
+ POSIX ERE dialect (the dialect typically used by `egrep`).
+
+`password-regex`
+: The regular expression to use when waiting for the password prompt. This
+ parameter is optional. If not specified, a reasonable default built into
+ Guacamole will be used. The regular expression must be written in the
+ POSIX ERE dialect (the dialect typically used by `egrep`).
+
+`login-success-regex`
+: The regular expression to use when detecting that the login attempt has
+ succeeded. This parameter is optional. If specified, the terminal display
+ will not be shown to the user until text matching this regular expression
+ has been received from the telnet server. The regular expression must be
+ written in the POSIX ERE dialect (the dialect typically used by `egrep`).
+
+`login-failure-regex`
+: The regular expression to use when detecting that the login attempt has
+ failed. This parameter is optional. If specified, the connection will be
+ closed with an explicit login failure error if text matching this regular
+ expression has been received from the telnet server. The regular
+ expression must be written in the POSIX ERE dialect (the dialect typically
+ used by `egrep`).
+
+(adding-telnet)=
+
+#### Adding a telnet connection
+
+If you are using the default authentication built into Guacamole, and you wish
+to grant access to a telnet connection to a particular user, you need to locate
+the `<authorize>` section for that user within your `user-mapping.xml`, and add
+a section like the following within it:
+
+```xml
+<connection name="Unique Name">
+ <protocol>telnet</protocol>
+ <param name="hostname">localhost</param>
+ <param name="port">23</param>
+</connection>
+```
+
+If added exactly as above, a new connection named "`Unique Name`" will be
+available to the user associated with the `<authorize>` section containing it.
+The connection will use telnet to connect to localhost at port 23. Naturally,
+you will want to change some or all of these values.
+
+As telnet is inherently insecure compared to SSH, you should use SSH instead
+wherever possible. If Guacamole is set up to use HTTPS then communication with
+the Guacamole *client* will be encrypted, but communication between guacd and
+the telnet server will still be unencrypted. You should not use telnet unless
+the network between guacd and the telnet server is trusted.
+
+### Kubernetes
+
+Kubernetes provides an API for attaching to the console of a container over the
+network. As with SSH and telnet, Guacamole's Kubernetes support emulates a
+terminal on the server side which renders to the Guacamole client's display.
+
+Kubernetes support for Guacamole is provided by the libguac-client-kubernetes
+library, which will be installed as part of guacamole-server if the required
+dependencies are present during the build.
+
+:::{note}
+In addition to the Kubernetes-specific parameters below, Guacamole's Kubernetes
+support also accepts the parameters of several features that Guacamole provides
+for multiple protocols:
+
+* [](disable-clipboard)
+* [](graphical-recording)
+* [](typescripts)
+* [](stdin-pipe)
+* [](terminal-behavior)
+* [](terminal-display-settings)
+* [](wake-on-lan)
+:::
+
+
+(kubernetes-network-parameters)=
+
+#### Network/Container parameters
+
+Attaching to a Kubernetes container requires the hostname or IP address of the
+Kubernetes server and the name of the pod containing the container in question.
+By default, Guacamole will attach to the first container in the pod. If there
+are multiple containers in the pod, you may wish to also specify the container
+name.
+
+`hostname`
+: The hostname or IP address of the Kubernetes server
+ that Guacamole should connect to.
+
+`port`
+: The port the Kubernetes server is listening on for
+ API connections. *This parameter is optional.* If
+ omitted, port 8080 will be used by default.
+
+`namespace`
+: The name of the Kubernetes namespace of the pod containing the container
+ being attached to. *This parameter is optional.* If omitted, the namespace
+ "default" will be used.
+
+`pod`
+: The name of the Kubernetes pod containing with the container being
+ attached to.
+
+`container`
+: The name of the container to attach to. *This parameter is optional.* If
+ omitted, the first container in the pod will be used.
+
+`exec-command`
+: The command to run within the container, with input and output attached to
+ this command's process. *This parameter is optional.* If omitted, no
+ command will be run, and input/output will instead be attached to the main
+ process of the container.
+
+ When this parameter is specified, the behavior of the connection is
+ analogous to running {command}`kubectl exec`. When omitted, the behavior
+ is analogous to running {command}`kubectl attach`.
+
+(kubernetes-authentication)=
+
+#### Authentication and SSL/TLS
+
+If enabled, Kubernetes uses SSL/TLS for both encryption and authentication.
+Standard SSL/TLS client authentication requires both a client certificate and
+client key, which Guacamole will use to identify itself to the Kubernetes
+server. If the certificate used by Kubernetes is self-signed or signed by a
+non-standard certificate authority, the certificate for the certificate
+authority will also be needed.
+
+`use-ssl`
+: If set to "true", SSL/TLS will be used to connect to the Kubernetes
+ server. *This parameter is optional.* By default, SSL/TLS will not be
+ used.
+
+`client-cert`
+: The certificate to use if performing SSL/TLS client authentication to
+ authenticate with the Kubernetes server, in PEM format. *This parameter is
+ optional.* If omitted, SSL client authentication will not be performed.
+
+`client-key`
+: The key to use if performing SSL/TLS client authentication to authenticate
+ with the Kubernetes server, in PEM format. *This parameter is optional.*
+ If omitted, SSL client authentication will not be performed.
+
+`ca-cert`
+: The certificate of the certificate authority that signed the certificate
+ of the Kubernetes server, in PEM format. *This parameter is optional.* If
+ omitted, verification of the Kubernetes server certificate will use only
+ system-wide certificate authorities.
+
+`ignore-cert`
+: If set to "true", the validity of the SSL/TLS certificate used by the
+ Kubernetes server will be ignored if it cannot be validated. *This
+ parameter is optional.* By default, SSL/TLS certificates are validated.
+
+(adding-kubernetes)=
+
+#### Adding a Kubernetes connection
+
+If you are using the default authentication built into Guacamole, and you wish
+to grant access to a Kubernetes connection to a particular user, you need to
+locate the `<authorize>` section for that user within your `user-mapping.xml`,
+and add a section like the following within it:
+
+```xml
+<connection name="Unique Name">
+ <protocol>kubernetes</protocol>
+ <param name="hostname">localhost</param>
+ <param name="pod">mypod</param>
+</connection>
+```
+
+If added exactly as above, a new connection named "`Unique Name`" will be
+available to the user associated with the `<authorize>` section containing it.
+The connection will connect to the Kubernetes server running on localhost and
+attach to the first container of the pod "mypod".
+
+### Common configuration options
+
+(disable-clipboard)=
+
+#### Disabling clipboard access
+
+Guacamole provides bidirectional access to the clipboard by default for all
+supported protocols. For protocols that don't inherently provide a clipboard,
+Guacamole implements its own clipboard. This behavior can be overridden on a
+per-connection basis with the `disable-copy` and `disable-paste` parameters.
+
+`disable-copy`
+: If set to "true", text copied within the remote desktop session will not
+ be accessible by the user at the browser side of the Guacamole session,
+ and will be usable only within the remote desktop. This parameter is
+ optional. By default, the user will be given access to the copied text.
+
+`disable-paste`
+: If set to "true", text copied at the browser side of the Guacamole session
+ will not be accessible within the remote ddesktop session. This parameter
+ is optional. By default, the user will be able to paste data from outside
+ the browser within the remote desktop session.
+
+(common-sftp)=
+
+#### File transfer via SFTP
+
+Guacamole can provide file transfer over SFTP even when the remote desktop is
+otherwise being accessed through a different protocol, like VNC or RDP. If SFTP
+is enabled on a Guacamole RDP connection, users will be able to upload and
+download files as described in [](using-guacamole).
+
+This support is independent of the file transfer that may be provided by the
+protocol in use, like RDP's own "drive redirection" (RDPDR), and is
+particularly useful for remote desktop servers which do not support file
+transfer features.
+
+`enable-sftp`
+: Whether file transfer should be enabled. If set to "true", the user will
+ be allowed to upload or download files from the specified server using
+ SFTP. If omitted, SFTP will be disabled.
+
+`sftp-hostname`
+: The hostname or IP address of the server hosting SFTP. This parameter is
+ optional. If omitted, the hostname of the remote desktop server associated
+ with the connection will be used.
+
+`sftp-port`
+: The port the SSH server providing SFTP is listening on, usually 22. This
+ parameter is optional. If omitted, the standard port of 22 will be used.
+
+`sftp-host-key`
+: The known hosts entry for the SFTP server. This parameter is optional,
+ and, if not provided, no verification of SFTP host identity will be done.
+ If the parameter is provided the identity of the server will be checked
+ against the data.
+
+ The format of this parameter is that of a single entry from an OpenSSH
+ `known_hosts` file.
+
+ For more information, please see [](ssh-host-verification).
+
+`sftp-username`
+: The username to authenticate as when connecting to the specified SSH
+ server for SFTP. This parameter is optional if a username is specified for
+ the remote desktop connection. If omitted, the username specified for the
+ remote desktop connection will be used.
+
+`sftp-password`
+: The password to use when authenticating with the specified SSH server for
+ SFTP.
+
+`sftp-private-key`
+: The entire contents of the private key to use for public key
+ authentication. If this parameter is not specified, public key
+ authentication will not be used. The private key must be in OpenSSH
+ format, as would be generated by the OpenSSH {command}`ssh-keygen`
+ utility.
+
+`sftp-passphrase`
+: The passphrase to use to decrypt the private key for use in public key
+ authentication. This parameter is not needed if the private key does not
+ require a passphrase.
+
+`sftp-directory`
+: The directory to upload files to if they are simply dragged and dropped,
+ and thus otherwise lack a specific upload location. This parameter is
+ optional. If omitted, the default upload location of the SSH server
+ providing SFTP will be used.
+
+`sftp-root-directory`
+: The directory to expose to connected users via Guacamole's
+ [](file-browser). If omitted, the root directory will be used by default.
+
+`sftp-server-alive-interval`
+: The interval in seconds at which to send keepalive packets to the SSH
+ server for the SFTP connection. This parameter is optional. If omitted,
+ the default of 0 will be used, disabling sending keepalive packets. The
+ minimum value is 2.
+
+`sftp-disable-download`
+: If set to true downloads from the remote system to the client (browser)
+ will be disabled. The default is false, which means that downloads will be
+ enabled.
+
+ If sftp is not enabled, this parameter will be ignored.
+
+`sftp-disable-upload`
+: If set to true uploads from the client (browser) to the remote system will
+ be disabled. The default is false, which means that uploads will be
+ enabled.
+
+ If sftp is not enabled, this parameter will be ignored.
+
+(graphical-recording)=
+
+#### Graphical session recording
+
+Sessions of all supported protocols can be recorded graphically. These
+recordings take the form of Guacamole protocol dumps and are recorded
+automatically to a specified directory. Recordings can be subsequently
+translated to a normal video stream using the {program}`guacenc` utility
+provided with guacamole-server.
+
+For example, to produce a video called {samp}`{NAME}.m4v` from the recording
+"`NAME`", you would run:
+
+```console
+$ guacenc /path/to/recording/NAME
+```
+
+The {program}`guacenc` utility has additional options for overriding default
+behavior, including tweaking the output format, which are documented in detail
+within the manpage:
+
+```console
+$ man guacenc
+```
+
+If recording of key events is explicitly enabled using the
+`recording-include-keys` parameter, recordings can also be translated into
+human-readable interpretations of the keys pressed during the session using the
+{program}`guaclog` utility. The usage of {program}`guaclog` is analogous to
+{program}`guacenc`, and results in the creation of a new text file containing
+the interpreted events:
+
+```console
+$ guaclog /path/to/recording/NAME
+guaclog: INFO: Guacamole input log interpreter (guaclog) version 1.3.0
+guaclog: INFO: 1 input file(s) provided.
+guaclog: INFO: Writing input events from "/path/to/recording/NAME" to "/path/to/recording/NAME.txt" ...
+guaclog: INFO: All files interpreted successfully.
+$
+```
+
+:::{important}
+Guacamole will never overwrite an existing recording. If necessary, a numeric
+suffix like ".1", ".2", ".3", etc. will be appended to <NAME> to avoid
+overwriting an existing recording. If even appending a numeric suffix does not
+help, the session will simply not be recorded.
+:::
+
+`recording-path`
+: The directory in which screen recording files should be created. *If a
+ graphical recording needs to be created, then this parameter is required.*
+ Specifying this parameter enables graphical screen recording. If this
+ parameter is omitted, no graphical recording will be created.
+
+`create-recording-path`
+: If set to "true", the directory specified by the `recording-path`
+ parameter will automatically be created if it does not yet exist. Only the
+ final directory in the path will be created - if other directories earlier
+ in the path do not exist, automatic creation will fail, and an error will
+ be logged.
+
+ *This parameter is optional.* By default, the directory specified by the
+ `recording-path` parameter will not automatically be created, and attempts
+ to create recordings within a non-existent directory will be logged as
+ errors.
+
+ This parameter only has an effect if graphical recording is enabled. If
+ the `recording-path` is not specified, graphical session recording will be
+ disabled, and this parameter will be ignored.
+
+`recording-name`
+: The filename to use for any created recordings. *This parameter is
+ optional.* If omitted, the value "recording" will be used instead.
+
+ This parameter only has an effect if graphical recording is enabled. If
+ the `recording-path` is not specified, graphical session recording will be
+ disabled, and this parameter will be ignored.
+
+`recording-exclude-output`
+: If set to "true", graphical output and other data normally streamed from
+ server to client will be excluded from the recording, producing a
+ recording which contains only user input events. *This parameter is
+ optional.* If omitted, graphical output will be included in the recording.
+
+ This parameter only has an effect if graphical recording is enabled. If
+ the `recording-path` is not specified, graphical session recording will be
+ disabled, and this parameter will be ignored.
+
+`recording-exclude-mouse`
+: If set to "true", user mouse events will be excluded from the recording,
+ producing a recording which lacks a visible mouse cursor. *This parameter
+ is optional.* If omitted, mouse events will be included in the recording.
+
+ This parameter only has an effect if graphical recording is enabled. If
+ the `recording-path` is not specified, graphical session recording will be
+ disabled, and this parameter will be ignored.
+
+`recording-include-keys`
+: If set to "true", user key events will be included in the recording. The
+ recording can subsequently be passed through the {program}`guaclog` utility
+ to produce a human-readable interpretation of the keys pressed during the
+ session. *This parameter is optional.* If omitted, key events will be not
+ included in the recording.
+
+ This parameter only has an effect if graphical recording is enabled. If
+ the `recording-path` is not specified, graphical session recording will be
+ disabled, and this parameter will be ignored.
+
+(typescripts)=
+
+#### Text session recording (typescripts)
+
+The full, raw text content of SSH sessions, including timing information, can
+be recorded automatically to a specified directory. This recording, also known
+as a "typescript", will be written to two files within the directory specified
+by `typescript-path`: {samp}`{NAME}`, which contains the raw text data, and
+{samp}`{NAME}.timing`, which contains timing information, where `NAME` is the
+value provided for the `typescript-name` parameter.
+
+This format is compatible with the format used by the standard UNIX
+{command}`script` command, and can be replayed using {command}`scriptreplay`
+(if installed). For example, to replay a typescript called "`NAME`", you would
+run:
+
+```console
+$ scriptreplay NAME.timing NAME
+```
+
+:::{important}
+Guacamole will never overwrite an existing recording. If necessary, a numeric
+suffix like ".1", ".2", ".3", etc. will be appended to `NAME` to avoid
+overwriting an existing recording. If even appending a numeric suffix does not
+help, the session will simply not be recorded.
+:::
+
+`typescript-path`
+: The directory in which typescript files should be created. *If a
+ typescript needs to be recorded, this parameter is required.* Specifying
+ this parameter enables typescript recording. If this parameter is omitted,
+ no typescript will be recorded.
+
+`create-typescript-path`
+: If set to "true", the directory specified by the `typescript-path`
+ parameter will automatically be created if it does not yet exist. Only the
+ final directory in the path will be created - if other directories earlier
+ in the path do not exist, automatic creation will fail, and an error will
+ be logged.
+
+ *This parameter is optional.* By default, the directory specified by the
+ `typescript-path` parameter will not automatically be created, and
+ attempts to record typescripts in a non-existent directory will be logged
+ as errors.
+
+ This parameter only has an effect if typescript recording is enabled. If
+ the `typescript-path` is not specified, recording of typescripts will be
+ disabled, and this parameter will be ignored.
+
+`typescript-name`
+: The base filename to use when determining the names for the data and
+ timing files of the typescript. *This parameter is optional.* If omitted,
+ the value "typescript" will be used instead.
+
+ Each typescript consists of two files which are created within the
+ directory specified by `typescript-path`: {samp}`{NAME}`, which contains
+ the raw text data, and {samp}`{NAME}.timing`, which contains timing
+ information, where `NAME` is the value provided for the `typescript-name`
+ parameter.
+
+ This parameter only has an effect if typescript recording is enabled. If
+ the `typescript-path` is not specified, recording of typescripts will be
+ disabled, and this parameter will be ignored.
+
+(terminal-behavior)=
+
+#### Controlling terminal behavior
+
+In most cases, the default behavior for a terminal works without modification.
+However, when connecting to certain systems, particularly operating systems
+other than Linux, the terminal behavior may need to be tweaked to allow it to
+operate properly. The settings in this section control that behavior.
+
+`backspace`
+: This parameter controls the ASCII code that the backspace key sends to the
+ remote system. Under most circumstances this should not need to be
+ adjusted; however, if, when pressing the backspace key, you see control
+ characters (often either ^? or ^H) instead of seeing the text erased, you
+ may need to adjust this parameter. By default the terminal sends ASCII
+ code 127 (Delete) if this option is not set.
+
+`terminal-type`
+: This parameter sets the terminal emulator type string that is passed to
+ the server. This parameter is optional. If not specified, "`linux`" is used
+ as the terminal emulator type by default.
+
+(stdin-pipe)=
+
+##### Providing terminal input directly from JavaScript
+
+If Guacamole is being used in part to automate an SSH, telnet, or other
+terminal session, it can be useful to provide input directly from JavaScript as
+a raw stream of data, rather than attempting to translate data into keystrokes.
+This can be done through opening a pipe stream named "STDIN" within the
+connection using the [`createPipeStream()`](http://guacamole.apache.org/doc/guacamole-common-js/Guacamole.Client.html#createPipeStream)
+function of [`Guacamole.Client`](http://guacamole.apache.org/doc/guacamole-common-js/Guacamole.Client.html):
+
+```javascript
+var outputStream = client.createPipeStream('text/plain', 'STDIN');
+```
+
+The resulting [`Guacamole.OutputStream`](http://guacamole.apache.org/doc/guacamole-common-js/Guacamole.OutputStream.html)
+can then be used to stream data directly to the input of the terminal session,
+as if typed by the user:
+
+```javascript
+// Wrap output stream in writer
+var writer = new Guacamole.StringWriter(outputStream);
+
+// Send text
+writer.sendText("hello");
+
+// Send more text
+writer.sendText("world");
+
+// Close writer and stream
+writer.sendEnd();
+```
+
+(terminal-display-settings)=
+
+#### Terminal display settings
+
+Guacamole's terminal emulator (used by SSH, telnet, and Kubernetes support)
+provides options for configuring the font used and its size. In this case, *the
+chosen font must be installed on the server*, as it is the server that will
+handle rendering of characters to the terminal display, not the client.
+
+`color-scheme`
+: The color scheme to use for the terminal session. It consists of a
+ semicolon-separated series of name-value pairs. Each name-value pair is
+ separated by a colon and assigns a value to a color in the terminal
+ emulator palette. For example, to use blue text on white background by
+ default, and change the red color to a purple shade, you would specify:
+
+ ```
+ foreground: rgb:00/00/ff;
+ background: rgb:ff/ff/ff;
+ color9: rgb:80/00/80
+ ```
+
+ This format is similar to the color configuration format used by Xterm, so
+ Xterm color configurations can be easily adapted for Guacamole. This
+ parameter is optional. If not specified, Guacamole will render text as
+ gray over a black background.
+
+ Possible color names are:
+
+ `foreground`
+ : Set the default foreground color.
+
+ `background`
+ : Set the default background color.
+
+ {samp}`color{N}`
+ : Set the color at index `N` on the Xterm 256-color palette. For example,
+ `color9` refers to the red color.
+
+ Possible color values are:
+
+ {samp}`rgb:{RR}/{GG}/{BB}`
+ : Use the specified color in RGB format, with each component in
+ hexadecimal. For example, `rgb:ff/00/00` specifies the color red. Note
+ that each hexadecimal component can be one to four digits, but the
+ effective values are always zero-extended or truncated to two digits;
+ for example, `rgb:f/8/0`, `rgb:f0/80/00`, and `rgb:f0f/808/00f` all
+ refer to the same effective color.
+
+ {samp}`color{N}`
+ : Use the color currently assigned to index `N` on the Xterm 256-color
+ palette. For example, `color9` specifies the current red color. Note
+ that the color value is used rather than the color reference, so if
+ `color9` is changed later in the color scheme configuration, that new
+ color will not be reflected in this assignment.
+
+ For backward compatibility, Guacamole will also accept four special values as
+ the color scheme parameter:
+
+ `black-white`
+ : Black text over a white background.
+
+ `gray-black`
+ : Gray text over a black background. This is the default color scheme.
+
+ `green-black`
+ : Green text over a black background.
+
+ `white-black`
+ : White text over a black background.
+
+`font-name`
+: The name of the font to use. This parameter is optional. If not specified,
+ the default of "monospace" will be used instead.
+
+`font-size`
+: The size of the font to use, in points. This parameter is optional. If not
+ specified, the default of 12 will be used instead.
+
+`scrollback`
+: The maximum number of rows to allow within the terminal scrollback buffer.
+ This parameter is optional. If not specified, the scrollback buffer will
+ be limited to a maximum of 1000 rows.
+
+(wake-on-lan)=
+
+#### Wake-on-LAN
+
+Guacamole implements the support to send a "magic wake-on-lan packet" to a
+remote host prior to attempting to establish a connection with the host. The
+below parameters control the behavior of this functionality, which is disabled
+by default.
+
+:::{important}
+There are several factors that can impact the ability of Wake-on-LAN (WoL) to
+function correctly, many of which are outside the scope of Guacamole
+configuration. If you are configuring WoL within Guacamole you should also be
+familiar with the other components that need to be configured in order for it
+to function correctly.
+:::
+
+`wol-send-packet`
+: If set to "true", Guacamole will attempt to send the Wake-On-LAN packet
+ prior to establishing a connection. This parameter is optional. By
+ default, Guacamole will not send the WoL packet. Enabling this option
+ requires that the `wol-mac-addr` parameter also be configured, otherwise
+ the WoL packet will not be sent.
+
+`wol-mac-addr`
+: This parameter configures the MAC address that Guacamole will use in the
+ magic WoL packet to attempt to wake the remote system. If
+ `wol-send-packet` is enabled, this parameter is required or else the WoL
+ packet will not be sent.
+
+`wol-broadcast-addr`
+: This parameter configures the IPv4 broadcast address or IPv6 multicast
+ address that Guacamole will send the WoL packet to in order to wake the
+ host. This parameter is optional. If no value is provided, the default
+ local IPv4 broadcast address (255.255.255.255) will be used.
+
+`wol-udp-port`
+: This parameter configures the UDP port that will be set in the WoL packet.
+ In most cases the UDP port isn't processed by the system that will be
+ woken up; however, there are certain cases where it is useful for the port
+ to be set, as in situations where a router is listening for the packet and
+ can make routing decisions depending upon the port that is used. If not
+ configured the default UDP port 9 will be used.
+
+`wol-wait-time`
+: By default after the WoL packet is sent Guacamole will attempt immediately
+ to connect to the remote host. It may be desirable in certain scenarios to
+ have Guacamole wait before the initial connection in order to give the
+ remote system time to boot. Setting this parameter to a positive value
+ will cause Guacamole to wait the specified number of seconds before
+ attempting the initial connection. This parameter is optional.
+
+(parameter-tokens)=
+
+### Parameter tokens
+
+The values of connection parameters can contain "tokens" which will be replaced
+by Guacamole when used. These tokens allow the values of connection parameters
+to vary dynamically by the user using the connection, and provide a simple
+means of forwarding authentication information without storing that information
+in the connection configuration itself, so long as the remote desktop
+connection uses the same credentials as Guacamole.
+
+Each token is of the form {samp}`$\{{TOKEN_NAME}\}` or
+{samp}`$\{{TOKEN_NAME}:{MODIFIER}\}`, where `TOKEN_NAME` is some descriptive
+name for the value the token represents, and the optional `MODIFIER` is one of
+the modifiers documented below to dynamically modify the token. Tokens with no
+corresponding value will never be replaced, but should you need such text
+within your connection parameters, and wish to guarantee that this text will
+not be replaced with a token value, you can escape the token by adding an
+additional leading "$", as in "{samp}`$$\{{TOKEN_NAME}\}`".
+
+`${GUAC_USERNAME}`
+: The username of the current Guacamole user. When a user accesses a
+ connection, this token will be dynamically replaced with the username they
+ provided when logging in to Guacamole.
+
+`${GUAC_PASSWORD}`
+: The password of the current Guacamole user. When a user accesses a
+ connection, this token will be dynamically replaced with the password they
+ used when logging in to Guacamole.
+
+`${GUAC_CLIENT_ADDRESS}`
+: The IPv4 or IPv6 address of the current Guacamole user. This will be the
+ address of the client side of the HTTP connection to the Guacamole server
+ at the time the current user logged in.
+
+`${GUAC_CLIENT_HOSTNAME}`
+: The hostname of the current Guacamole user. This will be the hostname of
+ the client side of the HTTP connection to the Guacamole server at the time
+ the current user logged in. If no such hostname can be determined, the
+ IPv4 or IPv6 address will be used instead, and this token will be
+ equivalent to `${GUAC_CLIENT_ADDRESS}`.
+
+`${GUAC_DATE}`
+: The current date in the local time zone of the Guacamole server. This will
+ be written in "YYYYMMDD" format, where "YYYY" is the year, "MM" is the
+ month number, and "DD" is the day of the month, all zero-padded. When a
+ user accesses a connection, this token will be dynamically replaced with
+ the date that the connection began.
+
+`${GUAC_TIME}`
+: The current time in the local time zone of the Guacamole server. This will
+ be written in "HHMMSS" format, where "HH" is hours in 24-hour time, "MM"
+ is minutes, and "SS" is seconds, all zero-padded. When a user accesses a
+ connection, this token will be dynamically replaced with the time that the
+ connection began.
+
+Note that these tokens are replaced dynamically each time a connection is used.
+If two different users access the same connection at the same time, both users
+will be connected independently of each other using different sets of
+connection parameters.
+
+#### Token modifiers
+
+At times it can be useful to use the value provided by a token, but with slight
+modifications. These modifers are optionally specified at the end of the token,
+separated from the token name by a colon (`:`), in the format
+{samp}`$\{{TOKEN_NAME}:{MODIFIER}\}`. The following modifiers are currently
+supported:
+
+`LOWER`
+: Convert the entire value of the token to lower-case. This can be useful in
+ situations where users log in to Guacamole with a mixed-case username, but
+ a remote system requires the username be lower-case.
+
+`UPPER`
+: Convert the entire value of the token to upper-case.
+
+(extension-tokens)=
+
+#### Extension-specific tokens
+
+Each extension can also implement its own arbitrary tokens that can
+dynamically fill in values provided by the extension. Within these
+extensions, attribute names are canonicalized into a standard format
+that consists of all capital letters separated by underscores.
+
+(cas-tokens)=
+
+##### CAS Extension Tokens
+
+The CAS extension will read attributes provided by the CAS server when a user
+is authenticated and will make those attributes available as tokens. The CAS
+server must be specifically configured to release certain attributes to the
+client (Guacamole), and configuration of that is outside the scope of this
+document. Any attribute that the CAS server is configured to release should be
+available to Guacamole as a token for use within a connection. The token name
+will be prepended with the `CAS_` prefix. A CAS server configured to release
+attributes `firstname`, `lastname`, `email`, and `mobile` would produce the
+following tokens:
+
+* `${CAS_FIRSTNAME}`
+* `${CAS_LASTNAME}`
+* `${CAS_EMAIL}`
+* `${CAS_MOBILE}`
+
+(ldap-tokens)=
+
+##### LDAP Extension Tokens
+
+The LDAP extension will read user attributes provided by the LDAP server and
+specified in the `guacamole.properties` file. The attributes retrieved for a
+user are configured using the `ldap-user-attributes` parameter. The user must
+be able to read the attribute values from their own LDAP object. The token name
+will be prepended with the `LDAP_` prefix. As an example, configuring the
+following line in `guacamole.properties`:
+
+```
+ldap-user-attributes: cn, givenName, sn, mobile, mail
+```
+
+will produce the below tokens that can be used in connection parameters:
+
+* `${LDAP_CN}`
+* `${LDAP_GIVENNAME}`
+* `${LDAP_SN}`
+* `${LDAP_MOBILE}`
+* `${LDAP_MAIL}`
+
+### Parameter prompting
+
+In certain situations Guacamole may determine that additional information is
+required in order to successfully open or continue a connection. In these
+scenarios guacd will send an instruction back to the client to retrieve that
+information, which will result in the user being prompted for those additional
+parameters.
+
+Currently the only parameters that will trigger this prompt to the user are
+authentication requests for the RDP and VNC protocols where authenticators were
+not provided as part of the connection configuration.
+
+:::{important}
+It is important to note that requests for parameters will only be generated in
+the case where that information has not already been provided as part of the
+connection. **The user will never be asked for parameters that replace or
+override connection parameters where values have been provided**, including
+authentication information.
+
+For example, if the configuration of a connection to a RDP server specifies a
+username and password, and that username or password is incorrect and results
+in an authentication failure, Guacamole will not prompt the user for additional
+credentials. For RDP servers where NLA is enforced, this will result in a
+connection failure. Other RDP servers may behave differently and give the user
+the ability to try other credentials, but this is outside the control of
+Guacamole - **Guacamole will not override pre-configured authentication values
+with input from the user**.
+:::
+
+(guacd.conf)=
+
+Configuring guacd
+-----------------
+
+### `guacd.conf`
+
+guacd is configured with a configuration file called `guacd.conf`, by
+default located in `/etc/guacamole`. This file follows a simple,
+INI-like format:
+
+```
+#
+# guacd configuration file
+#
+
+[daemon]
+
+pid_file = /var/run/guacd.pid
+log_level = info
+
+[server]
+
+bind_host = localhost
+bind_port = 4822
+
+#
+# The following parameters are valid only if
+# guacd was built with SSL support.
+#
+
+[ssl]
+
+server_certificate = /etc/ssl/certs/guacd.crt
+server_key = /etc/ssl/private/guacd.key
+```
+
+Configuration options are given as parameter/value pairs, where the name of the
+parameter is specified on the left side of an "`=`", and the value is specified
+on the right. Each parameter must occur within a proper section, indicated by a
+section name within brackets. The names of these sections are important; it is
+the pairing of a section name with a parameter that constitutes the
+fully-qualified parameter being set.
+
+For the sake of documentation and readability, comments can be added anywhere
+within guacd.conf using "`#`" symbols. All text following a "`#`" until
+end-of-line will be ignored.
+
+If you need to include special characters within the value of a parameter, such
+as whitespace or any of the above symbols, you can do so by placing the
+parameter within double quotes:
+
+```
+[ssl]
+
+# Whitespace is legal within double quotes ...
+server_certificate = "/etc/ssl/my certs/guacd.crt"
+
+# ... as are other special symbols
+server_key = "/etc/ssl/#private/guacd.key"
+```
+
+Note that even within double quotes, some characters still have special
+meaning, such as the double quote itself or newline characters. If you need to
+include these, they must be "escaped" with a backslash:
+
+```
+# Parameter value containing a double quote
+parameter = "some\"value"
+
+# Parameter value containing newline characters
+parameter2 = "line1\
+line2\
+line3"
+
+# Parameter value containing backslashes
+parameter3 = "c:\\windows\\path\\to\\file.txt"
+```
+
+Don't worry too much about the more complex formatting examples - they are only
+rarely necessary, and guacd will complain with parsing errors if the
+configuration file is somehow invalid. To ensure parameter values are entered
+correctly, just follow the following guidelines:
+
+1. If the value contains no special characters, just include it as-is.
+
+2. If the value contains any special characters (whitespace, newlines, `#`,
+ `\`, or `"`), enclose the entire value within double quotes.
+
+3. If the value is enclosed within double quotes, escape newlines, `\`, and `"`
+ with a backslash.
+
+(guacd-conf-daemon)=
+
+#### `[daemon]` section
+
+`pid_file`
+: The name of the file in which the PID of the main guacd process should be
+ written. This is mainly needed for startup scripts, which need to monitor
+ the state of guacd, killing it if necessary. If this parameter is
+ specified, the user running guacd must have sufficient permissions to
+ create or modify the specified file, or startup will fail.
+
+`log_level`
+: The maximum level at which guacd will log messages to syslog and, if
+ running in the foreground, the console. If omitted, the default level of
+ `info` will be used.
+
+ Legal values are `trace`, `debug`, `info`, `warning`, and `error`.
+
+(guacd-conf-server)=
+
+#### `[server]` section
+
+`bind_host`
+: The host that guacd should bind to when listening for connections. If
+ unspecified, guacd will bind to localhost, and only connections from
+ within the server hosting guacd will succeed.
+
+`bind_port`
+: The port that guacd should bind to when listening for connections. If
+ unspecified, port 4822 will be used.
+
+(guacd-conf-ssl)=
+
+#### `[ssl]` section
+
+`server_certificate`
+: The filename of the certificate to use for SSL encryption of the Guacamole
+ protocol. If this option is specified, SSL encryption will be enabled, and
+ the Guacamole web application will need to be configured within
+ `guacamole.properties` to use SSL as well.
+
+`server_key`
+: The filename of the private key to use for SSL encryption of the Guacamole
+ protocol. If this option is specified, SSL encryption will be enabled, and
+ the Guacamole web application will need to be configured within
+ `guacamole.properties` to use SSL as well.
+
+### Command-line options
+
+You can also affect the configuration of guacd with command-line
+options. If given, these options take precendence over the system-wide
+configuration file:
+
+{samp}`-b {HOST}`
+: Changes the host or address that guacd listens on.
+
+ This corresponds to the `bind_host` parameter within the [`[server]` section
+ of `guacd.conf`](guacd-conf-server).
+
+{samp}`-l {PORT}`
+: Changes the port that guacd listens on (the default is port 4822).
+
+ This corresponds to the `bind_port` parameter within the [`[server]` section
+ of `guacd.conf`](guacd-conf-server).
+
+{samp}`-p {PIDFILE}`
+: Causes guacd to write the PID of the daemon process to the specified file.
+ This is useful for init scripts and is used by the provided init script.
+
+ This corresponds to the `pid_file` parameter within the [`[daemon]` section
+ of `guacd.conf`](guacd-conf-daemon).
+
+{samp}`-L {LEVEL}`
+: Sets the maximum level at which guacd will log messages to syslog and, if
+ running in the foreground, the console. Legal values are `trace`, `debug`,
+ `info`, `warning`, and `error`. The default value is `info`.
+
+ This corresponds to the `log_level` parameter within the [`[daemon]` section
+ of `guacd.conf`](guacd-conf-daemon).
+
+`-f`
+: Causes guacd to run in the foreground, rather than automatically forking
+ into the background.
+
+If guacd was built with support for SSL, data sent via the Guacamole protocol
+can be encrypted with SSL if an SSL certificate and private key are given with
+the following options:
+
+{samp}`-C {CERTIFICATE}`
+: The filename of the certificate to use for SSL encryption of the Guacamole
+ protocol. If this option is specified, SSL encryption will be enabled, and
+ the Guacamole web application will need to be configured within
+ `guacamole.properties` to use SSL as well.
+
+ This corresponds to the `server_certificate` parameter within the [`[ssl]`
+ section of `guacd.conf`](guacd-conf-ssl).
+
+{samp}`-K {KEY}`
+: The filename of the private key to use for SSL encryption of the Guacamole
+ protocol. If this option is specified, SSL encryption will be enabled, and
+ the Guacamole web application will need to be configured within
+ `guacamole.properties` to use SSL as well.
+
+ This corresponds to the `server_key` parameter within the [`[ssl]` section of
+ `guacd.conf`](guacd-conf-ssl).
+
diff --git a/src/custom-auth.md b/src/custom-auth.md
new file mode 100644
index 0000000..ad8005d
--- /dev/null
+++ b/src/custom-auth.md
@@ -0,0 +1,495 @@
+Custom authentication
+=====================
+
+Guacamole's authentication layer is designed to be extendable such that users
+can integrate Guacamole into existing authentication systems without having to
+resort to writing their own web application around the Guacamole API.
+
+The web application comes with a default authentication mechanism which uses an
+XML file to associate users with connections. Extensions for Guacamole that
+provide LDAP-based authentication or database-based authentication have also
+been developed.
+
+To demonstrate the principles involved, we will implement a very simple
+authentication extension which associates a single user/password pair with a
+single connection, with all this information saved in properties inside the
+`guacamole.properties` file.
+
+In general, all other authentication extensions for Guacamole will use the
+principles demonstrated here. This tutorial demonstrates the simplest way to
+create an authentication extension for Guacamole - an authentication extension
+that does not support management of users and connections via the web
+interface.
+
+(custom-auth-model)=
+
+Guacamole's authentication model
+--------------------------------
+
+When you view any page in Guacamole, whether that be the login screen or the
+client interface, the page makes an authentication attempt with the web
+application, sending all available credentials. After entering your username
+and password, the exact same process occurs, except the web application
+receives the username and password as well.
+
+The web application handles this authentication attempt by collecting all
+credentials available and passing them to designated classes called
+"authentication providers". Given the set of credentials, authentication
+providers return a context object that provides restricted access to other
+users and connections, if any.
+
+(custom-auth-skeleton)=
+
+A Guacamole extension skeleton
+------------------------------
+
+For simplicity's sake, and because this is how things are done upstream in the
+Guacamole project, we will use Maven to build our extension.
+
+The bare minimum required for a Guacamole authentication extension is a
+`pom.xml` file listing guacamole-ext as a dependency, a single .java file
+implementing our stub of an authentication provider, and a `guac-manifest.json`
+file describing the extension and pointing to our authentication provider
+class.
+
+In our stub, we won't actually do any authentication yet; we'll just
+universally reject all authentication attempts by returning `null` for any
+credentials given. You can verify that this is what happens by checking the
+server logs.
+
+```xml
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.guacamole</groupId>
+ <artifactId>guacamole-auth-tutorial</artifactId>
+ <packaging>jar</packaging>
+ <version>1.3.0</version>
+ <name>guacamole-auth-tutorial</name>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <build>
+ <plugins>
+
+ <!-- Written for Java 8 -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.3</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <dependencies>
+
+ <!-- Guacamole Extension API -->
+ <dependency>
+ <groupId>org.apache.guacamole</groupId>
+ <artifactId>guacamole-ext</artifactId>
+ <version>1.3.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
+```
+
+We won't need to update this `pom.xml` throughout the rest of the tutorial.
+Even after adding new files, Maven will just find them and compile as
+necessary.
+
+Naturally, we need the actual authentication extension skeleton code. While
+you can put this in whatever file and package you want, for the sake of this
+tutorial, we will assume you are using
+`org.apache.guacamole.auth.TutorialAuthenticationProvider`.
+
+```java
+package org.apache.guacamole.auth;
+
+import java.util.Map;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.simple.SimpleAuthenticationProvider;
+import org.apache.guacamole.net.auth.Credentials;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+
+/**
+ * Authentication provider implementation intended to demonstrate basic use
+ * of Guacamole's extension API. The credentials and connection information for
+ * a single user are stored directly in guacamole.properties.
+ */
+public class TutorialAuthenticationProvider extends SimpleAuthenticationProvider {
+
+ @Override
+ public String getIdentifier() {
+ return "tutorial";
+ }
+
+ @Override
+ public Map<String, GuacamoleConfiguration>
+ getAuthorizedConfigurations(Credentials credentials)
+ throws GuacamoleException {
+
+ // Do nothing ... yet
+ return null;
+
+ }
+
+}
+```
+
+To conform with Maven, this skeleton file must be placed within
+`src/main/java/org/apache/guacamole/auth` as
+`TutorialAuthenticationProvider.java`.
+
+Notice how simple the authentication provider is. The
+`SimpleAuthenticationProvider` base class simplifies the
+`AuthenticationProvider` interface, requiring nothing more than a unique
+identifier (we will use "tutorial") and a single getAuthorizedConfigurations()
+implementation, which must return a `Map` of `GuacamoleConfiguration` each
+associated with some arbitrary unique ID. This unique ID will be presented to
+the user in the connection list after they log in.
+
+For now, `getAuthorizedConfigurations()` will just return `null`. This will
+cause Guacamole to report an invalid login for every attempt. Note that there
+is a difference in semantics between returning an empty map and returning
+`null`, as the former indicates the credentials are authorized but simply have
+no associated configurations, while the latter indicates the credentials are
+not authorized at all.
+
+The only remaining piece for the overall skeleton to be complete is a
+`guac-manifest.json` file. *This file is absolutely required for all Guacamole
+extensions.* The `guac-manifest.json` format is described in more detail in
+[](guacamole-ext). It provides for quite a few properties, but for our
+authentication extension we are mainly interested in the Guacamole version
+sanity check (to make sure an extension built for the API of Guacamole version
+X is not accidentally used against version Y) and telling Guacamole where to
+find our authentication provider class.
+
+The Guacamole extension format requires that `guac-manifest.json` be placed in
+the root directory of the extension `.jar` file. To accomplish this with Maven,
+we place it within the `src/main/resources` directory. Maven will automatically
+pick it up during the build and include it within the `.jar`.
+
+```json
+{
+
+ "guacamoleVersion" : "1.3.0",
+
+ "name" : "Tutorial Authentication Extension",
+ "namespace" : "guac-auth-tutorial",
+
+ "authProviders" : [
+ "org.apache.guacamole.auth.TutorialAuthenticationProvider"
+ ]
+
+}
+```
+
+(custom-auth-building)=
+
+Building the extension
+----------------------
+
+Once all three of the above files are in place, the extension will build, and
+can even be installed within Guacamole (see [](custom-auth-installing) at the
+end of this chapter), even though it is just a skeleton at this point. It won't
+do anything yet other than reject all authentication attempts, but it's good to
+at least try building the extension to make sure nothing is missing and that
+all steps have been followed correctly so far:
+
+```console
+$ mvn package
+[INFO] Scanning for projects...
+[INFO] ------------------------------------------------------------------------
+[INFO] Building guacamole-auth-tutorial 1.3.0
+[INFO] ------------------------------------------------------------------------
+...
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD SUCCESS
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 2.345 s
+[INFO] Finished at: 2015-12-16T13:39:00-08:00
+[INFO] Final Memory: 14M/138M
+[INFO] ------------------------------------------------------------------------
+$
+```
+
+Assuming you see the "`BUILD SUCCESS`" message when you build the extension,
+there will be a new file, `target/guacamole-auth-tutorial-1.3.0.jar`, which can
+be installed within Guacamole and tested. If you changed the name or version of
+the project in the `pom.xml` file, the name of this new `.jar` file will be
+different, but it can still be found within `target/`.
+
+(custom-auth-config)=
+
+Configuration and authentication
+--------------------------------
+
+Once we receive credentials, we need to validate those credentials against the
+associated properties in `guacamole.properties` (our source of authentication
+information for the sake of this tutorial).
+
+We will define four properties:
+
+`tutorial-user`
+: The name of the only user we accept.
+
+`tutorial-password`
+: The password we require for the user specified to be authenticated.
+
+`tutorial-protocol`
+: The protocol of the configuration this user is authorized to use, which
+ will be sent to guacd when the user logs in and selects their connection.
+
+`tutorial-parameters`
+: A comma-delimited list of `name=value` pairs. For the sake of simplicity,
+ we'll assume there will never be any commas in the values.
+
+If the username and password match what is stored in the file, we read the
+configuration information, store it in a `GuacamoleConfiguration`, and return
+the configuration within a set, telling Guacamole that this user is authorized
+but only to access the configurations returned.
+
+Upstream, we always place the properties of authentication providers in their
+own class, and so we will also do that here in this tutorial, as it keeps
+things organized.
+
+```java
+package org.apache.guacamole.auth;
+
+import org.apache.guacamole.properties.StringGuacamoleProperty;
+
+/**
+ * Utility class containing all properties used by the custom authentication
+ * tutorial. The properties defined here must be specified within
+ * guacamole.properties to configure the tutorial authentication provider.
+ */
+public class TutorialGuacamoleProperties {
+
+ /**
+ * This class should not be instantiated.
+ */
+ private TutorialGuacamoleProperties() {}
+
+ /**
+ * The only user to allow.
+ */
+ public static final StringGuacamoleProperty TUTORIAL_USER =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "tutorial-user"; }
+
+ };
+
+ /**
+ * The password required for the specified user.
+ */
+ public static final StringGuacamoleProperty TUTORIAL_PASSWORD =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "tutorial-password"; }
+
+ };
+
+
+ /**
+ * The protocol to use when connecting.
+ */
+ public static final StringGuacamoleProperty TUTORIAL_PROTOCOL =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "tutorial-protocol"; }
+
+ };
+
+
+ /**
+ * All parameters associated with the connection, as a comma-delimited
+ * list of name="value"
+ */
+ public static final StringGuacamoleProperty TUTORIAL_PARAMETERS =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "tutorial-parameters"; }
+
+ };
+
+}
+```
+
+Normally, we would define a new type of `GuacamoleProperty` to handle the
+parsing of the parameters required by `TUTORIAL_PARAMETERS`, but for the sake
+of simplicity, parsing of this parameter will be embedded in the authentication
+function later.
+
+You will need to modify your existing `guacamole.properties` file, adding each
+of the above properties to describe one of your available connections.
+
+```
+# Username and password
+tutorial-user: tutorial
+tutorial-password: password
+
+# Connection information
+tutorial-protocol: vnc
+tutorial-parameters: hostname=localhost, port=5900
+```
+
+Once these properties and their accessor class are in place, it's simple enough
+to read the properties within `getAuthorizedConfigurations()` and authenticate
+the user based on their username and password.
+
+```java
+@Override
+public Map<String, GuacamoleConfiguration>
+ getAuthorizedConfigurations(Credentials credentials)
+ throws GuacamoleException {
+
+ // Get the Guacamole server environment
+ Environment environment = new LocalEnvironment();
+
+ // Get username from guacamole.properties
+ String username = environment.getRequiredProperty(
+ TutorialGuacamoleProperties.TUTORIAL_USER
+ );
+
+ // If wrong username, fail
+ if (!username.equals(credentials.getUsername()))
+ return null;
+
+ // Get password from guacamole.properties
+ String password = environment.getRequiredProperty(
+ TutorialGuacamoleProperties.TUTORIAL_PASSWORD
+ );
+
+ // If wrong password, fail
+ if (!password.equals(credentials.getPassword()))
+ return null;
+
+ // Successful login. Return configurations (STUB)
+ return new HashMap<String, GuacamoleConfiguration>();
+
+}
+```
+
+As is, the authentication provider will work in its current state in that the
+correct username and password will authenticate the user, while an incorrect
+username or password will not, but we still aren't returning an actual map of
+configurations. We need to construct the configuration based on the properties
+in the `guacamole.properties` file after the user has been authenticated, and
+return that configuration to the web application.
+
+(custom-auth-more-config)=
+
+Parsing the configuration
+-------------------------
+
+The only remaining task before we have a fully-functioning authentication
+provider is to actually parse the configuration from the `guacamole.properties`
+file.
+
+```java
+@Override
+public Map<String, GuacamoleConfiguration>
+ getAuthorizedConfigurations(Credentials credentials)
+ throws GuacamoleException {
+
+ // Get the Guacamole server environment
+ Environment environment = new LocalEnvironment();
+
+ // Get username from guacamole.properties
+ String username = environment.getRequiredProperty(
+ TutorialGuacamoleProperties.TUTORIAL_USER
+ );
+
+ // If wrong username, fail
+ if (!username.equals(credentials.getUsername()))
+ return null;
+
+ // Get password from guacamole.properties
+ String password = environment.getRequiredProperty(
+ TutorialGuacamoleProperties.TUTORIAL_PASSWORD
+ );
+
+ // If wrong password, fail
+ if (!password.equals(credentials.getPassword()))
+ return null;
+
+ // Successful login. Return configurations.
+ Map<String, GuacamoleConfiguration> configs =
+ new HashMap<String, GuacamoleConfiguration>();
+
+ // Create new configuration
+ GuacamoleConfiguration config = new GuacamoleConfiguration();
+
+ // Set protocol specified in properties
+ config.setProtocol(environment.getRequiredProperty(
+ TutorialGuacamoleProperties.TUTORIAL_PROTOCOL
+ ));
+
+ // Set all parameters, splitting at commas
+ for (String parameterValue : environment.getRequiredProperty(
+ TutorialGuacamoleProperties.TUTORIAL_PARAMETERS
+ ).split(",\\s*")) {
+
+ // Find the equals sign
+ int equals = parameterValue.indexOf('=');
+ if (equals == -1)
+ throw new GuacamoleServerException("Required equals sign missing");
+
+ // Get name and value from parameter string
+ String name = parameterValue.substring(0, equals);
+ String value = parameterValue.substring(equals+1);
+
+ // Set parameter as specified
+ config.setParameter(name, value);
+
+ }
+
+ configs.put("Tutorial Connection", config);
+ return configs;
+
+}
+```
+
+The extension is now complete and can be built as described earlier in
+[](custom-auth-building).
+
+(custom-auth-installing)=
+
+Installing the extension
+------------------------
+
+Guacamole extensions are self-contained `.jar` files which are installed by
+being placed within `GUACAMOLE_HOME/extensions`, and this extension is no
+different. As described in [](configuring-guacamole), `GUACAMOLE_HOME` is a
+placeholder used to refer to the directory that Guacamole uses to locate its
+configuration files and extensions. Typically, this will be the `.guacamole`
+directory within the home directory of the user running Tomcat.
+
+To install your extension, ensure that the required properties have been added
+to your `guacamole.properties`, copy the
+`target/guacamole-auth-tutorial-1.3.0.jar` file into
+`GUACAMOLE_HOME/extensions` and restart Tomcat. Guacamole will automatically
+load your extension, logging an informative message that it has done so:
+
+```
+Extension "Tutorial Authentication Extension" loaded.
+```
+
diff --git a/src/custom-protocols.md b/src/custom-protocols.md
new file mode 100644
index 0000000..5fa10ad
--- /dev/null
+++ b/src/custom-protocols.md
@@ -0,0 +1,828 @@
+Adding new protocols
+====================
+
+Guacamole's support for multiple remote desktop protocols is provided through
+plugins which guacd loads dynamically. The Guacamole API has been designed such
+that protocol support is easy to create, especially when a C library exists
+providing a basic client implementation.
+
+In this tutorial, we will implement a simple "client" which renders a bouncing
+ball using the Guacamole protocol. After completing the tutorial and installing
+the result, you will be able to add a connection to your Guacamole
+configuration using the "ball" protocol, and any users using that connection
+will see a bouncing ball.
+
+This example client plugin doesn't actually act as a client, but this isn't
+important. The Guacamole client is really just a remote display, and this
+client plugin functions as a simple example application which renders to this
+display, just as Guacamole's own VNC or RDP plugins function as VNC or RDP
+clients which render to the remote display.
+
+Each step of this tutorial is intended to exercise a new concept, while also
+progressing towards the goal of a nifty bouncing ball. At the end of each step,
+you will have a buildable and working client plugin.
+
+This tutorial will use the GNU Automake build system, which is the build system
+used by Guacamole for libguac, guacd, etc. There will be four files involved:
+
+`configure.ac`
+: Used by GNU Automake to generate the `configure` script which ultimately
+ serves to generate the `Makefile` which {command}`make` will use when
+ building.
+
+`Makefile.am`
+: Used by GNU Automake and the `configure` script to generate the `Makefile`
+ which {command}`make` will use when building.
+
+`src/ball.c`
+: The main body of code defining the bouncing ball "client".
+
+`src/ball.h`
+: A header file defining the structure representing the state of the bouncing
+ ball (once it becomes necessary to do so).
+
+All source files will be within the `src` subdirectory, as is common with C
+projects, with build files being at the root level directory. The main
+`src/ball.c` and the build-related `configure.ac` and `Makefile.am` files will
+be created first, with each successive step building upon those files
+iteratively, with `src/ball.h` being added when it becomes necessary. After
+each step, you can build/rebuild the plugin by running {command}`make`, and
+then install it (such that guacd can find the plugin) by running {command}`make
+install` and {command}`ldconfig` as root:
+
+```console
+$ make
+ CC src/ball.lo
+ CCLD libguac-client-ball.la
+# make install
+make[1]: Entering directory '/home/user/libguac-client-ball'
+ /usr/bin/mkdir -p '/usr/local/lib'
+ /bin/sh ./libtool --mode=install /usr/bin/install -c libguac-client-ball.la '/usr/local/lib'
+...
+----------------------------------------------------------------------
+Libraries have been installed in:
+ /usr/local/lib
+
+If you ever happen to want to link against installed libraries
+in a given directory, LIBDIR, you must either use libtool, and
+specify the full pathname of the library, or use the '-LLIBDIR'
+flag during linking and do at least one of the following:
+ - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable
+ during execution
+ - add LIBDIR to the 'LD_RUN_PATH' environment variable
+ during linking
+ - use the '-Wl,-rpath -Wl,LIBDIR' linker flag
+ - have your system administrator add LIBDIR to '/etc/ld.so.conf'
+
+See any operating system documentation about shared libraries for
+more information, such as the ld(1) and ld.so(8) manual pages.
+----------------------------------------------------------------------
+make[1]: Nothing to be done for 'install-data-am'.
+make[1]: Leaving directory '/home/user/libguac-client-ball'
+# ldconfig
+```
+
+Prior to the first time {command}`make` is invoked, you will need to run the
+`configure` script, which will first need to be generated using
+{command}`autoreconf`:
+
+```console
+$ autoreconf -fi
+libtoolize: putting auxiliary files in '.'.
+libtoolize: copying file './ltmain.sh'
+libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
+libtoolize: copying file 'm4/libtool.m4'
+libtoolize: copying file 'm4/ltoptions.m4'
+libtoolize: copying file 'm4/ltsugar.m4'
+libtoolize: copying file 'm4/ltversion.m4'
+libtoolize: copying file 'm4/lt~obsolete.m4'
+configure.ac:10: installing './compile'
+configure.ac:4: installing './missing'
+Makefile.am: installing './depcomp'
+$ ./configure
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+...
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: executing depfiles commands
+config.status: executing libtool commands
+$
+```
+
+This process is almost identical to that of building guacamole-server from git,
+as documented in [](building-guacamole-server).
+
+:::{important}
+The libguac library which is part of guacamole-server is a required dependency
+of this project. *You must first install libguac, guacd, etc. by [building and
+installing guacamole-server](building-guacamole-server)*. If guacamole-server
+has not been installed, and libguac is thus not present, the `configure` script
+will fail with an error indicating that it could not find libguac:
+
+```console
+$ ./configure
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+...
+checking for guac_client_stream_png in -lguac... no
+configure: error: "libguac is required for communication via "
+ "the Guacamole protocol"
+$
+```
+
+You will need to install guacamole-server and then rerun `configure`.
+:::
+
+(libguac-client-ball-skeleton)=
+
+Minimal skeleton client
+-----------------------
+
+Very little needs to be done to implement the most basic client plugin
+possible. We begin with `src/ball.c`, containing the absolute minimum required
+for a client plugin:
+
+```c
+#include <guacamole/client.h>
+
+#include <stdlib.h>
+
+/* Client plugin arguments (empty) */
+const char* TUTORIAL_ARGS[] = { NULL };
+
+int guac_client_init(guac_client* client) {
+
+ /* This example does not implement any arguments */
+ client->args = TUTORIAL_ARGS;
+
+ return 0;
+
+}
+```
+
+Notice the structure of this file. There is exactly one function,
+`guac_client_init`, which is the entry point for all Guacamole client plugins.
+Just as a typical C program has a main function which is executed when the
+program is run, a Guacamole client plugin has `guac_client_init` which is
+called when guacd loads the plugin when a new connection is made and your
+protocol is selected.
+
+`guac_client_init` receives a single `guac_client` which it must initialize.
+Part of this initialization process involves declaring the list of arguments
+that joining users can specify. While we won't be using arguments in this
+tutorial, and thus the arguments assigned above are simply an empty list, a
+typical client plugin implementation would register arguments which define the
+remote desktop connection and its behavior. Examples of such parameters can be
+seen in the connection parameters for the protocols supported by Guacamole
+out-of-the-box (see [](connection-configuration)).
+
+The `guac_client` instance given to `guac_client_init` will be shared by the
+user that starts the connection, and any users which join the connection via
+screen sharing. It lives until the connection is explicitly closed, or until
+all users leave the connection.
+
+For this project to build with GNU Automake, we a `configure.ac` file which
+describes the name of the project and what it needs configuration-wise. In
+this case, the project is "libguac-client-ball", and it depends on the
+"libguac" library used by guacd and all client plugins:
+
+```
+# Project information
+AC_PREREQ([2.61])
+AC_INIT([libguac-client-ball], [0.1.0])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
+AM_SILENT_RULES([yes])
+
+AC_CONFIG_MACRO_DIRS([m4])
+
+# Check for required build tools
+AC_PROG_CC
+AC_PROG_CC_C99
+AC_PROG_LIBTOOL
+
+# Check for libguac
+AC_CHECK_LIB([guac], [guac_client_stream_png],,
+ AC_MSG_ERROR("libguac is required for communication via "
+ "the Guacamole protocol"))
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+```
+
+We also need a `Makefile.am`, describing which files should be built and how
+when building libguac-client-ball:
+
+```
+AUTOMAKE_OPTIONS = foreign
+
+ACLOCAL_AMFLAGS = -I m4
+AM_CFLAGS = -Werror -Wall -pedantic
+
+lib_LTLIBRARIES = libguac-client-ball.la
+
+# All source files of libguac-client-ball
+libguac_client_ball_la_SOURCES = src/ball.c
+
+# libtool versioning information
+libguac_client_ball_la_LDFLAGS = -version-info 0:0:0
+```
+
+The GNU Automake files will remain largely unchanged throughout the rest of the
+tutorial.
+
+Once you have created all of the above files, you will have a functioning
+client plugin. It doesn't do anything yet, and any connection will be extremely
+short-lived (the lack of any data sent by the server will lead to the client
+disconnecting under the assumption that the connection has stopped responding),
+but it does technically work.
+
+(libguac-client-ball-display-init)=
+
+Initializing the remote display
+-------------------------------
+
+Now that we have a basic functioning skeleton, we need to actually do something
+with the remote display. A good first step would be simply initializing the
+display - setting the remote display size and providing a basic background.
+
+In this case, we'll set the display to a nice default of 1024x768, and fill the
+background with gray. Though the size of the display *can* be chosen based on
+the size of the user's browser window (which is provided by the user during the
+[Guacamole protocol handshake](guacamole-protocol-handshake), or even updated
+when the window size changes (provided by the user via ["size"
+instructions](client-size-instruction)), we won't be doing that here for
+simplicity's sake:
+
+```c
+#include <guacamole/client.h>
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+#include <guacamole/user.h>
+
+#include <stdlib.h>
+
+...
+
+int ball_join_handler(guac_user* user, int argc, char** argv) {
+
+ /* Get client associated with user */
+ guac_client* client = user->client;
+
+ /* Get user-specific socket */
+ guac_socket* socket = user->socket;
+
+ /* Send the display size */
+ guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, 1024, 768);
+
+ /* Prepare a curve which covers the entire layer */
+ guac_protocol_send_rect(socket, GUAC_DEFAULT_LAYER,
+ 0, 0, 1024, 768);
+
+ /* Fill curve with solid color */
+ guac_protocol_send_cfill(socket,
+ GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
+ 0x80, 0x80, 0x80, 0xFF);
+
+ /* Mark end-of-frame */
+ guac_protocol_send_sync(socket, client->last_sent_timestamp);
+
+ /* Flush buffer */
+ guac_socket_flush(socket);
+
+ /* User successfully initialized */
+ return 0;
+
+}
+
+int guac_client_init(guac_client* client) {
+
+ /* This example does not implement any arguments */
+ client->args = TUTORIAL_ARGS;
+
+ /* Client-level handlers */
+ client->join_handler = ball_join_handler;
+
+ return 0;
+
+}
+```
+
+The most important thing to notice here is the new `ball_join_handler()`
+function. As it is assigned to `join_handler` of the `guac_client` given to
+`guac_client_init`, users which join the connection (including the user that
+opened the connection in the first place) will be passed to this function. It
+is the duty of the join handler to initialize the provided `guac_user`, taking
+into account any arguments received from the user during the connection
+handshake (exposed through `argc` and `argv` to the join handler). We aren't
+implementing any arguments, so these values are simply ignored, but we do need
+to initialize the user with respect to display state. In this case, we:
+
+1. Send a ["size" instruction](size-instruction), initializing the display size
+ to 1024x768.
+
+2. Draw a 1024x768 gray rectangle over the display using the
+ ["rect"](rect-instruction) and ["cfill"](cfill-instruction) instructions.
+
+3. Send a ["sync" instruction](sync-instruction), informing the remote display
+ that a frame has been completed.
+
+4. Flush the socket, ensuring that all data written to the socket thus far is
+ immediately sent to the user.
+
+At this point, if you build, install, and connect using the plugin, you will
+see a gray screen. The connection will still be extremely short-lived, however,
+since the only data ever sent by the plugin is sent when the user first joins.
+The lack of any data sent by the server over the remaining life of the
+connection will lead to the client disconnecting under the assumption that the
+connection has stopped responding. This will be rectified shortly once we add
+the bouncing ball.
+
+(libguac-client-ball-layer)=
+
+Adding the ball
+---------------
+
+This tutorial is about making a bouncing ball "client", so naturally we need a
+ball to bounce. While we could repeatedly draw and erase a ball on the remote
+display, a more efficient technique would be to leverage Guacamole's layers.
+
+The remote display has a single root layer, `GUAC_DEFAULT_LAYER`, but there can
+be infinitely many other child layers, which can themselves have child layers,
+and so on. Each layer can be dynamically repositioned within and relative to
+another layer. Because the compositing of these layers is handled by the remote
+display, and is likely hardware-accelerated, this is a much better way to
+repeatedly reposition something we expect to move a lot.
+
+Since we're finally adding the ball, and there needs to be some structure which
+maintains the state of the ball, we must create a header file,
+`src/ball.h`, to define this:
+
+```c
+#ifndef BALL_H
+#define BALL_H
+
+#include <guacamole/layer.h>
+
+typedef struct ball_client_data {
+
+ guac_layer* ball;
+
+} ball_client_data;
+
+#endif
+```
+
+To make the build system aware of the existence of the new `src/ball.h` header
+file, `Makefile.am` must be updated as well:
+
+```
+...
+
+# All source files of libguac-client-ball
+noinst_HEADERS = src/ball.h
+libguac_client_ball_la_SOURCES = src/ball.c
+
+...
+```
+
+This new structure is intended to house the client-level state of the ball,
+independent of any users which join or leave the connection. The structure must
+be allocated when the client begins (within `guac_client_init`), freed when the
+client terminates (via a new client free handler), and must contain the layer
+which represents the ball within the remote display. As this layer is part of
+the remote display state, it must additionally be initialized when a user
+joins, in the same way that the display overall was initialized in earlier
+steps:
+
+```c
+#include "ball.h"
+
+#include <guacamole/client.h>
+#include <guacamole/layer.h>
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+#include <guacamole/user.h>
+
+#include <stdlib.h>
+
+...
+
+int ball_join_handler(guac_user* user, int argc, char** argv) {
+
+ /* Get client associated with user */
+ guac_client* client = user->client;
+
+ /* Get ball layer from client data */
+ ball_client_data* data = (ball_client_data*) client->data;
+ guac_layer* ball = data->ball;
+
+ ...
+
+ /* Set up ball layer */
+ guac_protocol_send_size(socket, ball, 128, 128);
+
+ /* Prepare a curve which covers the entire layer */
+ guac_protocol_send_rect(socket, ball,
+ 0, 0, 128, 128);
+
+ /* Fill curve with solid color */
+ guac_protocol_send_cfill(socket,
+ GUAC_COMP_OVER, ball,
+ 0x00, 0x80, 0x80, 0xFF);
+
+ /* Mark end-of-frame */
+ guac_protocol_send_sync(socket, client->last_sent_timestamp);
+
+ /* Flush buffer */
+ guac_socket_flush(socket);
+
+ /* User successfully initialized */
+ return 0;
+
+}
+
+int ball_free_handler(guac_client* client) {
+
+ ball_client_data* data = (ball_client_data*) client->data;
+
+ /* Free client-level ball layer */
+ guac_client_free_layer(client, data->ball);
+
+ /* Free client-specific data */
+ free(data);
+
+ /* Data successfully freed */
+ return 0;
+
+}
+
+int guac_client_init(guac_client* client) {
+
+ /* Allocate storage for client-specific data */
+ ball_client_data* data = malloc(sizeof(ball_client_data));
+
+ /* Set up client data and handlers */
+ client->data = data;
+
+ /* Allocate layer at the client level */
+ data->ball = guac_client_alloc_layer(client);
+
+ ...
+
+ /* Client-level handlers */
+ client->join_handler = ball_join_handler;
+ client->free_handler = ball_free_handler;
+
+ return 0;
+
+}
+```
+
+The allocate/free pattern for the client-specific data and layers should be
+pretty straightforward - the allocation occurs when the objects (the layer and
+the structure housing it) are first needed, and the allocated objects are freed
+once they are no longer needed (when the client terminates) to avoid leaking
+memory. The initialization of the ball layer using the Guacamole protocol
+should be familiar as well - it's identical to the way the screen was
+initialized, and involves the same instructions.
+
+Beyond layers, Guacamole has the concept of buffers, which are identical in use
+to layers except they are invisible. Buffers are used to store image data for
+the sake of caching or drawing operations. We will use them later when we try
+to make this tutorial prettier. If you build and install the ball client as-is
+now, you will see a large gray rectangle (the root layer) with a small blue
+square in the upper left corner (the ball layer).
+
+(libguac-client-ball-bounce)=
+
+Making the ball bounce
+----------------------
+
+To make the ball bounce, we need to track the ball's state, including current
+position and velocity, as well as a thread which updates the ball's state (and
+the remote display) as time progresses. The ball state and thread can be stored
+alongside the ball layer in the existing client-level data structure:
+
+```c
+...
+
+#include <guacamole/layer.h>
+
+#include <pthread.h>
+
+typedef struct ball_client_data {
+
+ guac_layer* ball;
+
+ int ball_x;
+ int ball_y;
+
+ int ball_velocity_x;
+ int ball_velocity_y;
+
+ pthread_t render_thread;
+
+} ball_client_data;
+
+...
+```
+
+The contents of the thread will update these values at a pre-defined rate,
+changing ball position with respect to velocity, and changing velocity with
+respect to collisions with the display boundaries:
+
+```c
+#include "ball.h"
+
+#include <guacamole/client.h>
+#include <guacamole/layer.h>
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+#include <guacamole/user.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+
+...
+
+void* ball_render_thread(void* arg) {
+
+ /* Get data */
+ guac_client* client = (guac_client*) arg;
+ ball_client_data* data = (ball_client_data*) client->data;
+
+ /* Update ball position as long as client is running */
+ while (client->state == GUAC_CLIENT_RUNNING) {
+
+ /* Sleep a bit */
+ usleep(30000);
+
+ /* Update position */
+ data->ball_x += data->ball_velocity_x * 30 / 1000;
+ data->ball_y += data->ball_velocity_y * 30 / 1000;
+
+ /* Bounce if necessary */
+ if (data->ball_x < 0) {
+ data->ball_x = -data->ball_x;
+ data->ball_velocity_x = -data->ball_velocity_x;
+ }
+ else if (data->ball_x >= 1024 - 128) {
+ data->ball_x = (2 * (1024 - 128)) - data->ball_x;
+ data->ball_velocity_x = -data->ball_velocity_x;
+ }
+
+ if (data->ball_y < 0) {
+ data->ball_y = -data->ball_y;
+ data->ball_velocity_y = -data->ball_velocity_y;
+ }
+ else if (data->ball_y >= 768 - 128) {
+ data->ball_y = (2 * (768 - 128)) - data->ball_y;
+ data->ball_velocity_y = -data->ball_velocity_y;
+ }
+
+ guac_protocol_send_move(client->socket, data->ball,
+ GUAC_DEFAULT_LAYER, data->ball_x, data->ball_y, 0);
+
+ /* End frame and flush socket */
+ guac_client_end_frame(client);
+ guac_socket_flush(client->socket);
+
+ }
+
+ return NULL;
+
+}
+
+...
+```
+
+Just as with the join handler, this thread sends a "sync" instruction to denote
+the end of each frame, though here this is accomplished with
+`guac_client_end_frame()`. This function sends a "sync" containing the current
+timestamp, and updates the properties of the `guac_client` with the last-sent
+timestamp (the value that our join handler uses to send *its* sync). Note that
+we don't redraw the whole display with each frame - we simply update the
+position of the ball layer using a ["move" instruction](move-instruction), and
+rely on the remote display to handle compositing on its own.
+
+We now need to update `guac_client_init` to actually create this thread,
+initialize the ball state within the structure, and store the thread for future
+cleanup when the client terminates:
+
+```c
+...
+
+int ball_free_handler(guac_client* client) {
+
+ ball_client_data* data = (ball_client_data*) client->data;
+
+ /* Wait for render thread to terminate */
+ pthread_join(data->render_thread, NULL);
+
+ ...
+
+}
+
+int guac_client_init(guac_client* client) {
+
+ ...
+
+ /* Start ball at upper left */
+ data->ball_x = 0;
+ data->ball_y = 0;
+
+ /* Move at a reasonable pace to the lower right */
+ data->ball_velocity_x = 200; /* pixels per second */
+ data->ball_velocity_y = 200; /* pixels per second */
+
+ /* Start render thread */
+ pthread_create(&data->render_thread, NULL, ball_render_thread, client);
+
+ ...
+
+}
+```
+
+The thread contains a render loop which continually checks the state property
+of the `guac_client`. This property is set to `GUAC_CLIENT_RUNNING` when the
+connection begins, and remains that way for the duration of the connection.
+When guacd needs to terminate the connection (such as when the last user
+leaves), the value will change to `GUAC_CLIENT_STOPPING`. The free handler
+we've written can thus rely on `pthread_join()` to block until the data
+previously used by the plugin is no longer being used and can safely be freed.
+
+Once built and installed, our ball client now has a bouncing ball, albeit a
+very square and plain one. Now that the display is continually updating, and
+data is being continually received from the server, connected clients will no
+longer automatically disconnect.
+
+(libguac-client-ball-pretty)=
+
+A prettier ball
+---------------
+
+Now that we have our ball bouncing, we might as well try to make it actually
+look like a ball, and try applying some of the fancier graphics features that
+Guacamole offers. Guacamole provides instructions common to most 2D drawing
+APIs, including HTML5's canvas and Cairo. This means you can draw arcs, curves,
+apply fill and stroke, and even use the contents of another layer or buffer as
+the pattern for a fill or stroke. In complex cases involving many draw
+operations, it will actually be more efficient to render to a server-side Cairo
+surface and send only image data to the client, but it's perfect for relatively
+simple cases like our ball.
+
+We will try creating a simple gray checkerboard pattern in a buffer, using that
+for the background instead of the previous gray rectangle, and will modify the
+ball by replacing the rectangle with an arc, in this case a full circle,
+complete with stroke (border) and translucent-blue fill:
+
+```c
+int ball_join_handler(guac_user* user, int argc, char** argv) {
+
+ ...
+
+ /* Create background tile */
+ guac_layer* texture = guac_client_alloc_buffer(client);
+
+ guac_protocol_send_rect(socket, texture, 0, 0, 64, 64);
+ guac_protocol_send_cfill(socket, GUAC_COMP_OVER, texture,
+ 0x88, 0x88, 0x88, 0xFF);
+
+ guac_protocol_send_rect(socket, texture, 0, 0, 32, 32);
+ guac_protocol_send_cfill(socket, GUAC_COMP_OVER, texture,
+ 0xDD, 0xDD, 0xDD, 0xFF);
+
+ guac_protocol_send_rect(socket, texture, 32, 32, 32, 32);
+ guac_protocol_send_cfill(socket, GUAC_COMP_OVER, texture,
+ 0xDD, 0xDD, 0xDD, 0xFF);
+
+
+ /* Prepare a curve which covers the entire layer */
+ guac_protocol_send_rect(socket, GUAC_DEFAULT_LAYER,
+ 0, 0, 1024, 768);
+
+ /* Fill curve with texture */
+ guac_protocol_send_lfill(socket,
+ GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
+ texture);
+
+ /* Set up ball layer */
+ guac_protocol_send_size(socket, ball, 128, 128);
+
+ /* Prepare a circular curve */
+ guac_protocol_send_arc(socket, data->ball,
+ 64, 64, 62, 0, 6.28, 0);
+
+ guac_protocol_send_close(socket, data->ball);
+
+ /* Draw a 4-pixel black border */
+ guac_protocol_send_cstroke(socket,
+ GUAC_COMP_OVER, data->ball,
+ GUAC_LINE_CAP_ROUND, GUAC_LINE_JOIN_ROUND, 4,
+ 0x00, 0x00, 0x00, 0xFF);
+
+ /* Fill the circle with color */
+ guac_protocol_send_cfill(socket,
+ GUAC_COMP_OVER, data->ball,
+ 0x00, 0x80, 0x80, 0x80);
+
+ /* Free texture (no longer needed) */
+ guac_client_free_buffer(client, texture);
+
+ /* Mark end-of-frame */
+ guac_protocol_send_sync(socket, client->last_sent_timestamp);
+
+ ...
+
+}
+```
+
+Again, because we put the ball in its own layer, we don't have to worry about
+compositing it ourselves. The remote display will handle this, and will likely
+do so with hardware acceleration, even though the ball is now translucent.
+Build and install the ball client after this step, and you will have a rather
+nice-looking bouncing ball.
+
+(libguac-client-ball-time)=
+
+Handling the passage of time
+----------------------------
+
+There are never any guarantees when it comes to timing, threads, and network
+performance. We cannot necessarily rely on the remote display to handle updates
+in a timely manner (it may be slow), nor can we rely on the network or server
+to give priority to communication from guacd.
+
+The render thread needs to be modified to take this into account, by tracking
+the actual time spent within each frame, and estimating the amount of time the
+client spends rendering each frame:
+
+```c
+#include "ball.h"
+
+#include <guacamole/client.h>
+#include <guacamole/layer.h>
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+#include <guacamole/timestamp.h>
+#include <guacamole/user.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+
+...
+
+void* ball_render_thread(void* arg) {
+
+ ...
+
+ /* Init time of last frame to current time */
+ guac_timestamp last_frame = guac_timestamp_current();
+
+ /* Update ball position as long as client is running */
+ while (client->state == CLIENT_RUNNING) {
+
+ /* Default to 30ms frames */
+ int frame_duration = 30;
+
+ /* Lengthen frame duration if client is lagging */
+ int processing_lag = guac_client_get_processing_lag(client);
+ if (processing_lag > frame_duration)
+ frame_duration = processing_lag;
+
+ /* Sleep for duration of frame, then get timestamp */
+ usleep(frame_duration);
+ guac_timestamp current = guac_timestamp_current();
+
+ /* Calculate change in time */
+ int delta_t = current - last_frame;
+
+ /* Update position */
+ data->ball_x += data->ball_velocity_x * delta_t / 1000;
+ data->ball_y += data->ball_velocity_y * delta_t / 1000;
+
+ ...
+
+ /* Update timestamp */
+ last_frame = current;
+
+ }
+
+ ...
+
+}
+```
+
+The calculations are pretty simple. Rather than hard-code the duration of each
+frame, we us a default of 30 milliseconds, lengthening the frame if Guacamole's
+built-in lag estimation determines that the client is having trouble. The
+physics portion of the update no longer assumes that the frame will be exactly
+30 milliseconds, instead relying on the actual time elapsed since the previous
+frame.
+
+At this point, we now have a robust Guacamole client plugin. It handles
+joining/leaving users correctly, continually updates the remote display state
+while taking into account variable network/server/client conditions, and cleans
+up after itself when the connection finally terminates.
+
diff --git a/src/duo-auth.md b/src/duo-auth.md
new file mode 100644
index 0000000..e095b71
--- /dev/null
+++ b/src/duo-auth.md
@@ -0,0 +1,188 @@
+Duo two-factor authentication
+=============================
+
+Guacamole supports Duo as a second authentication factor, layered on top
+of any other authentication extension, including those available from
+the main project website. The Duo authentication extension allows users
+to be additionally verified against the Duo service before the
+authentication process is allowed to succeed.
+
+:::{important}
+This chapter involves modifying the contents of `GUACAMOLE_HOME` - the
+Guacamole configuration directory. If you are unsure where `GUACAMOLE_HOME` is
+located on your system, please consult [](configuring-guacamole) before
+proceeding.
+:::
+
+(duo-architecture)=
+
+How Duo works with Guacamole
+----------------------------
+
+Guacamole provides support for Duo as a second authentication factor. To
+make use of the Duo authentication extension, some other authentication
+mechanism will need be configured, as well. When a user attempts to log
+into Guacamole, other installed authentication methods will be queried
+first:
+
+
+
+Only after authentication has succeeded with one of those methods will
+Guacamole reach out to Duo to obtain additional verification of user
+identity:
+
+
+
+If both the initial authentication attempt and verification through Duo
+succeed, the user will be allowed in. If either mechanism fails, access
+to Guacamole is denied.
+
+(duo-downloading)=
+
+Downloading the Duo extension
+-----------------------------
+
+The Duo authentication extension is available separately from the main
+`guacamole.war`. The link for this and all other officially-supported
+and compatible extensions for a particular version of Guacamole are
+provided on the release notes for that version. You can find the release
+notes for current versions of Guacamole here:
+http://guacamole.apache.org/releases/.
+
+The Duo authentication extension is packaged as a `.tar.gz` file
+containing only the extension itself, `guacamole-auth-duo-1.3.0.jar`,
+which must ultimately be placed in `GUACAMOLE_HOME/extensions`.
+
+(installing-duo-auth)=
+
+Installing Duo authentication
+-----------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located
+within the `GUACAMOLE_HOME/extensions` directory. To install the Duo
+authentication extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+ exist.
+
+2. Copy `guacamole-auth-duo-1.3.0.jar` within `GUACAMOLE_HOME/extensions`.
+
+3. Configure Guacamole to use Duo authentication, as described below.
+
+:::{important}
+You will need to restart Guacamole by restarting your servlet container in
+order to complete the installation. Doing this will disconnect all active
+users, so be sure that it is safe to do so prior to attempting installation. If
+you do not configure the Duo authentication properly, Guacamole will not start
+up again until the configuration is fixed.
+:::
+
+### Adding Guacamole to Duo
+
+Duo does not provide a specific integration option for Guacamole, but
+Guacamole's Duo extension uses Duo's generic authentication API which
+they refer to as the "Web SDK". To use Guacamole with Duo, you will need
+to add it as a new "Web SDK" application from within the "Applications"
+tab of the admin panel of your Duo account:
+
+
+
+Within the settings of the newly-added application, rename the
+application to something more representative than "Web SDK". This
+application name is what will be presented to your users when they are
+prompted by Duo for additional authentication:
+
+
+
+Once you've finished adding Guacamole as an "Web SDK" application, the
+configuration information required to configure Guacamole is listed
+within the application's "Details" section. You will need to copy the
+integration key, secret key, and API hostname - they will later be
+specified within `guacamole.properties`:
+
+
+
+(guac-duo-config)=
+
+### Configuring Guacamole for Duo
+
+The application-specific configuration information retrieved from Duo
+must be added to `guacamole.properties` to describe how Guacamole
+should connect to the Duo service:
+
+duo-api-hostname
+: The hostname of the Duo API endpoint to be used to verify user identities.
+ This will usually be in the form `api-XXXXXXXX.duosecurity.com`, where
+ "XXXXXXXX" is some arbitrary alphanumeric value assigned by Duo. This
+ value will have been generated by Duo when you added Guacamole as an "Web
+ SDK" application, and can be found within the application details in the
+ "API hostname" field. *This value is required.*
+
+duo-integration-key
+: The integration key provided for Guacamole by Duo. This value will
+ have been generated by Duo when you added Guacamole as an "Web SDK"
+ application, and can be found within the application details in the
+ "Integration key" field. *This value is required and must be EXACTLY
+ 20 characters.*
+
+duo-secret-key
+: The secret key provided for Guacamole by Duo. This value will have
+ been generated by Duo when you added Guacamole as an "Web SDK"
+ application, and can be found within the application details in the
+ "Secret key" field. *This value is required and must be EXACTLY 40
+ characters.*
+
+In addition to the above, *you must also manually generate an
+"application key"*. The application key is required by Duo's
+authentication API, but is not provided by Duo. It is an arbitrary value
+meant to be unique to each deployment of an application using their API.
+
+duo-application-key
+: An arbitrary, random key which you manually generated for Guacamole.
+ *This value is required and must be AT LEAST 40 characters.*
+
+The application key can be generated with any method as long as it is
+sufficiently random. There exist utilities which will do this for you, like
+`pwgen`:
+
+```console
+$ pwgen 40 1
+em1io4zievohneeseiwah0zie2raQuoo2ci5oBoo
+$
+```
+
+Alternatively, one quick and fairly portable way to do this is to use the `dd`
+utility to copy random bytes from the secure random device `/dev/random`,
+sending the data through a cryptographic hash tool with a sufficiently-long
+result, like `sha256sum`:
+
+```console
+$ dd if=/dev/random count=1 | sha256sum
+5d16d6bb86da73e7d1abd3286b21dcf3b3e707532e64ceebc7a008350d0d485d -
+$
+```
+
+(completing-duo-install)=
+
+### Completing the installation
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before Duo authentication will take effect. Restart your servlet container and
+give the new authentication a try.
+
+:::{important}
+You only need to restart your servlet container. *You do not need to restart
+guacd*.
+
+guacd is completely independent of the web application and does not deal with
+`guacamole.properties` or the authentication system in any way. Since you are
+already restarting the servlet container, restarting guacd as well technically
+won't hurt anything, but doing so is completely pointless.
+:::
+
+If Guacamole does not come back online after restarting your servlet
+container, check the logs. Problems in the configuration of the Duo
+extension may prevent Guacamole from starting up, and any such errors
+will be recorded in the logs of your servlet container.
+
diff --git a/src/event-listeners.md b/src/event-listeners.md
new file mode 100644
index 0000000..b3f6b02
--- /dev/null
+++ b/src/event-listeners.md
@@ -0,0 +1,371 @@
+Event listeners
+===============
+
+Guacamole supports the delivery of event notifications to custom extensions.
+Developers can use listener extensions to integrate custom handling of events
+such as successful and failed authentications, and requests to connect and
+disconnect tunnels to desktop environments.
+
+A listener extension could be used, for example, to record authentication
+attempts in an external database for security auditing or alerting. By
+listening to tunnel lifecycle events, a listener extension could be used to
+help coordinate startup and shutdown of machine resources; particularly useful
+in cloud environments where minimizing running-but-idle resources is an
+important cost savings measure.
+
+For certain *vetoable* events, an event listener can even influence Guacamole's
+behavior. For example, a listener can veto a successful authentication,
+effectively causing the authentication to be considered failed. Similarly, a
+listener can veto a tunnel connection, effectively preventing the tunnel from
+being connected to a virtual desktop resource.
+
+Custom event listeners are packaged using the same extension mechanism used for
+custom authentication providers. A single listener extension can include any
+number of classes that implement the listener interface. A single extension
+module can also include any combination of authentication providers and
+listeners, so developers can easily combine authentication providers with
+listeners designed to support them.
+
+To demonstrate the principles involved in receiving Guacamole event
+notifications, we will implement a simple listener extension that logs
+authentication events. While our approach simply writes event details to the
+same log used by the Guacamole web application, a listener could process these
+events in arbitrary ways, limited only by the imagination and ingenuity of the
+developer.
+
+(custom-event-listener-skeleton)=
+
+A Guacamole listener extension skeleton
+---------------------------------------
+
+For simplicity's sake, and because this is how things are done upstream in the
+Guacamole project, we will use Maven to build our extension.
+
+The bare minimum required for a Guacamole listener extension is a `pom.xml`
+file listing guacamole-ext as a dependency, a single `.java` file implementing
+our stub of a listener, and a `guac-manifest.json` file describing the
+extension and pointing to our listener class.
+
+```xml
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.guacamole</groupId>
+ <artifactId>guacamole-listener-tutorial</artifactId>
+ <packaging>jar</packaging>
+ <version>1.3.0</version>
+ <name>guacamole-listener-tutorial</name>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <build>
+ <plugins>
+
+ <!-- Written for Java 8 -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.3</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <dependencies>
+
+ <!-- Guacamole Extension API -->
+ <dependency>
+ <groupId>org.apache.guacamole</groupId>
+ <artifactId>guacamole-ext</artifactId>
+ <version>1.3.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Slf4j API -->
+ <!-- This is needed only if your listener wants to
+ write to the Guacamole web application log -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.7</version>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
+```
+
+Naturally, we need the actual listener extension skeleton code. While you can
+put this in whatever file and package you want, for the sake of this tutorial,
+we will assume you are using `org.apache.guacamole.event.TutorialListener`.
+
+For now, we won't actually do anything other than log the fact that an event
+notification was received. At this point, we're just creating the skeleton for
+our listener extension.
+
+```java
+package org.apache.guacamole.event;
+
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.event.listener.Listener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Listener implementation intended to demonstrate basic use
+ * of Guacamole's listener extension API.
+ */
+public class TutorialListener implements Listener {
+
+ private static final Logger logger =
+ LoggerFactory.getLogger(TutorialListener.class);
+
+ @Override
+ public void handleEvent(Object event) throws GuacamoleException {
+ logger.info("received Guacamole event notification");
+ }
+
+}
+```
+
+To conform with Maven, this skeleton file must be placed within
+`src/main/java/org/apache/guacamole/event` as `TutorialListener.java`.
+
+As you can see, implementing a listener is quite simple. There is a single
+`Listener` interface to implement. All Guacamole event notifications will be
+delivered to your code by invoking the handleEvent method. We will see shortly
+how to use the passed event object to get the details of the event itself.
+
+The only remaining piece for the overall skeleton to be complete is a
+`guac-manifest.json` file. *This file is absolutely required for all Guacamole
+extensions.* The `guac-manifest.json` format is described in more detail in
+[](guacamole-ext). It provides for quite a few properties, but for our listener
+extension we are mainly interested in the Guacamole version sanity check (to
+make sure an extension built for the API of Guacamole version X is not
+accidentally used against version Y) and telling Guacamole where to find our
+listener class.
+
+The Guacamole extension format requires that `guac-manifest.json` be placed in
+the root directory of the extension `.jar` file. To accomplish this with Maven,
+we place it within the `src/main/resources` directory. Maven will automatically
+pick it up during the build and include it within the `.jar`.
+
+```json
+{
+
+ "guacamoleVersion" : "1.3.0",
+
+ "name" : "Tutorial Listener Extension",
+ "namespace" : "guac-listener-tutorial",
+
+ "listeners" : [
+ "org.apache.guacamole.event.TutorialListener"
+ ]
+
+}
+```
+
+(custom-listener-building)=
+
+Building the extension
+----------------------
+
+Once all three of the above files are in place, the extension should build
+successfully even though it is just a skeleton at this point.
+
+```console
+$ mvn package
+[INFO] Scanning for projects...
+[INFO] ---------------------------------------------------------------
+[INFO] Building guacamole-listener-tutorial 1.3.0
+[INFO] ---------------------------------------------------------------
+...
+[INFO] ---------------------------------------------------------------
+[INFO] BUILD SUCCESS
+[INFO] ---------------------------------------------------------------
+[INFO] Total time: 1.297 s
+[INFO] Finished at: 2017-10-08T13:12:39-04:00
+[INFO] Final Memory: 19M/306M
+[INFO] ---------------------------------------------------------------
+$
+```
+
+Assuming you see the "`BUILD SUCCESS`" message when you build the extension,
+there will be a new file, `target/guacamole-listener-tutorial-1.3.0.jar`, which
+can be installed within Guacamole (see [](custom-listener-installing) at the
+end of this chapter). It should log event notifications that occur during, for
+example, authentication attempts. If you changed the name or version of the
+project in the `pom.xml` file, the name of this new `.jar` file will be
+different, but it can still be found within `target/`.
+
+(custom-listener-event-handling)=
+
+Handling events
+---------------
+
+The Guacamole `Listener` interface represents a low-level event handling API. A
+listener is notified of every event generated by Guacamole. The listener must
+examine the event type to determine whether the event is of interest, and if so
+to dispatch the event to the appropriate entry point.
+
+The event types that can be produced by Guacamole are described in the
+`org.apache.guacamole.net.event` package of the guacamole-ext API. In this
+package you will find several concrete event types as well as interfaces that
+describe common characteristics of certain of event types. You can use any of
+these types to distinguish the events received by your listener, and to examine
+properties of an event of a given type.
+
+Suppose we wish to log authentication success and failure events, while
+ignoring all other event types. The `AuthenticationSuccessEvent` and
+`AuthenticationFailureEvent` types are used to notify a listener of
+authentication events. We can simply check whether a received event is of one
+of these types and, if so, log an appropriate message.
+
+```java
+package org.apache.guacamole.event;
+
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.event.AuthenticationFailureEvent;
+import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
+import org.apache.guacamole.net.event.listener.Listener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Listener that logs authentication success and failure events.
+ */
+public class TutorialListener implements Listener {
+
+ private static final Logger logger =
+ LoggerFactory.getLogger(TutorialListener.class);
+
+ @Override
+ public void handleEvent(Object event) throws GuacamoleException {
+
+ if (event instanceof AuthenticationSuccessEvent) {
+ logger.info("successful authentication for user {}",
+ ((AuthenticationSuccessEvent) event)
+ .getCredentials().getUsername());
+ }
+ else if (event instanceof AuthenticationFailureEvent) {
+ logger.info("failed authentication for user {}",
+ ((AuthenticationFailureEvent) event)
+ .getCredentials().getUsername());
+ }
+ }
+
+}
+```
+
+In our example, we use `instanceof` to check for the two event types of
+interest to our listener. Once we have identified an event of interest, we can
+safely cast the event type to access properties of the event.
+
+The extension is now complete and can be built as described earlier in
+[](custom-listener-building) and installed as described below in
+[](custom-listener-installing).
+
+(custom-listener-veto)=
+
+Influencing Guacamole by event veto
+-----------------------------------
+
+An implementation of the handleEvent method is permitted to throw any
+`GuacamoleException`. For certain *vetoable* event types, throwing a
+`GuacamoleException` serves to effectively veto the action that resulted in the
+event notification. See the API documentation for guacamole-ext to learn more
+about vetoable event types.
+
+As an (admittedly contrived) example, suppose we want to prevent a user named
+"guacadmin" from accessing Guacamole. For whatever reason, we don't wish to
+remove or disable the auth database entry for this user. In this case we can
+use a listener to block this user, preventing access to Guacamole. In the
+listener, when we get an `AuthenticationSuccessEvent` we can check to see if
+the user is "guacadmin" and, if so, throw an exception to prevent this user
+from logging in to Guacamole.
+
+```java
+package org.apache.guacamole.event;
+
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.net.event.AuthenticationFailureEvent;
+import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
+import org.apache.guacamole.net.event.listener.Listener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Listener that logs authentication success and failure events
+ * and prevents the "guacadmin" user from logging in by throwing
+ * a GuacamoleSecurityException.
+ */
+public class TutorialListener implements Listener {
+
+ private static final Logger logger =
+ LoggerFactory.getLogger(TutorialListener.class);
+
+ @Override
+ public void handleEvent(Object event) throws GuacamoleException {
+
+ if (event instanceof AuthenticationSuccessEvent) {
+ final String username = ((AuthenticationSuccessEvent) event)
+ .getCredentials().getUsername();
+
+ if ("guacadmin".equals(username)) {
+ logger.warn("user {} has been blocked", username);
+ throw new GuacamoleSecurityException(
+ "User '" + username + "' is currently blocked");
+ }
+
+ logger.info("successful authentication for user {}", username);
+ }
+ else if (event instanceof AuthenticationFailureEvent) {
+ logger.info("failed authentication for user {}",
+ ((AuthenticationFailureEvent) event)
+ .getCredentials().getUsername());
+ }
+ }
+
+}
+```
+
+If our Guacamole user database contains a user named "guacadmin", and we build
+and install this listener extension, we will find that an attempt to log in as
+this user now results in a message in the UI indicating that the user is
+blocked. If we examine the Guacamole log, we will see the message indicating
+that the user was blocked. Because the successful authentication was vetoed,
+Guacamole sends a subsequent authentication failure notification, which we see
+logged as well.
+
+(custom-listener-installing)=
+
+Installing the extension
+------------------------
+
+Guacamole extensions are self-contained `.jar` files which are installed by
+being placed within `GUACAMOLE_HOME/extensions`, and this extension is no
+different. As described in [](configuring-guacamole), `GUACAMOLE_HOME` is a
+placeholder used to refer to the directory that Guacamole uses to locate its
+configuration files and extensions. Typically, this will be the `.guacamole`
+directory within the home directory of the user running Tomcat.
+
+To install your extension, copy the
+`target/guacamole-listener-tutorial-1.3.0.jar` file into
+`GUACAMOLE_HOME/extensions` and restart Tomcat. Guacamole will automatically
+load your extension, logging an informative message that it has done so:
+
+```
+Extension "Tutorial Listener Extension" loaded.
+```
+
diff --git a/src/ext/guac.py b/src/ext/guac.py
new file mode 100644
index 0000000..908a84d
--- /dev/null
+++ b/src/ext/guac.py
@@ -0,0 +1,287 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from docutils.nodes import Element
+from docutils.parsers.rst import directives
+from typing import List, Tuple
+
+from sphinx import addnodes
+from sphinx.addnodes import pending_xref
+from sphinx.application import Sphinx
+from sphinx.builders import Builder
+from sphinx.directives import ObjectDescription
+from sphinx.domains import Domain, ObjType
+from sphinx.environment import BuildEnvironment
+from sphinx.roles import XRefRole
+from sphinx.util.docfields import TypedField
+from sphinx.util.nodes import make_refnode
+
+def phase(option_value):
+ """
+ Parses the given string, validating it against the set of valid Guacamole
+ protocol session phase identifier strings ("handshake" or "interactive").
+
+ :param option_value:
+ The string to parse, as may be received from Sphinx as the value of a
+ directive option.
+
+ :return string:
+ The provided, valid string.
+
+ :raises ValueError:
+ If the provided phase is invalid.
+ """
+ return directives.choice(option_value, ('handshake', 'interactive'))
+
+def endpoint(option_value):
+ """
+ Parses the given string, validating it against the set of valid endpoint
+ identifier strings ("client" or "server").
+
+ :param option_value:
+ The string to parse, as may be received from Sphinx as the value of a
+ directive option.
+
+ :return string:
+ The provided, valid string.
+
+ :raises ValueError:
+ If the provided endpoint is invalid.
+ """
+ return directives.choice(option_value, ('client', 'server'))
+
+def phase_set(option_value):
+ """
+ Parses the given string, converting it from a comma-separated list of
+ values into a Python set of Guacamole protocol session phase identifier
+ strings ("handshake" or "interactive").
+
+ :param option_value:
+ The string to parse, as may be received from Sphinx as the value of a
+ directive option.
+
+ :return set:
+ A Python set containing all phase identifier strings within the
+ provided comma-separated list.
+
+ :raises ValueError:
+ If any provided phase is invalid.
+ """
+ entries = directives.unchanged_required(option_value)
+ return { phase(entry) for entry in entries.split(',') }
+
+def endpoint_set(option_value):
+ """
+ Parses the given string, converting it from a comma-separated list of
+ values into a Python set of endpoint identifier strings ("client" or
+ "server").
+
+ :param option_value:
+ The string to parse, as may be received from Sphinx as the value of a
+ directive option.
+
+ :return set:
+ A Python set containing all endpoint identifier strings within the
+ provided comma-separated list.
+
+ :raises ValueError:
+ If any provided endpoint is invalid.
+ """
+ entries = directives.unchanged_required(option_value)
+ return { endpoint(entry) for entry in entries.split(',') }
+
+class GuacInstruction(ObjectDescription[Tuple[str, str]]):
+ """
+ Sphinx directive that represents a single Guacamole instruction. This
+ directive allows the Guacamole manual to document Guacamole protocol
+ instructions using minimal markup, just as the functions and structures of
+ a library might be documented.
+ """
+
+ # Each of the attributes below are defined and inherited from the
+ # superclass (ObjectDescription).
+
+ domain = 'guac'
+
+ doc_field_types = [
+ TypedField('argument',
+ label = "Arguments",
+ names = ['arg'],
+ can_collapse = True
+ )
+ ]
+
+ option_spec = {
+ 'phase' : phase_set,
+ 'sent-by' : endpoint_set
+ }
+
+ def get_phases(self):
+ """
+ Returns the set of Guacamole protocol phases in which this instruction
+ is valid, as declared by the "phase" directive option. An instruction
+ may be valid in multiple phases. If no phase is declared, the
+ "interactive" phase is assumed by default.
+
+ :return set:
+ The set of Guacamole protocol phases in which this instruction is
+ valid.
+ """
+ return self.options.get('phase', { 'interactive' })
+
+ def get_senders(self):
+ """
+ Returns the set of Guacamole protocol endpoints ("client" or "server")
+ that may send this instruction, as declared by the "sent-by" directive
+ option. An instruction may be sent by client, server, or both. If no
+ endpoint is declared, the "server" endpoint is assumed by default.
+
+ :return set:
+ The set of Guacamole protocol endpoints that may send this
+ instruction.
+ """
+ return self.options.get('sent-by', { 'server' })
+
+ def handle_signature(self, sig, signode):
+
+ # This function is inherited from the superclass (ObjectDescription).
+ # The implementation is expected to override this function to define
+ # the unique signature and name for the object being documented.
+
+ signode.clear()
+ signode += addnodes.desc_name(sig, sig)
+
+ # Generate an internal, unique name for referring to this instruction
+ # based on how the instruction is actually used (there may be multiple
+ # definitions having the same instruction opcode yet different meanings
+ # if sent by client vs. server or during the handshake vs. interactive
+ # phases)
+ unique_name = sig
+
+ # Add "client-" prefix for all client-specific instructions
+ if self.get_senders() == { 'client' }:
+ unique_name = 'client-' + unique_name
+
+ # Add "-handshake" suffix for all handshake-specific instructions
+ if self.get_phases() == { 'handshake' }:
+ unique_name += '-handshake'
+
+ # NOTE: This value will be passed as the name to add_target_and_index()
+ return unique_name
+
+ def add_target_and_index(self, name, sig, sig_node):
+
+ # This function is inherited from the superclass (ObjectDescription).
+ # The implementation is expected to override this function to define a
+ # unique ID for the object being documented, assigning that ID to the
+ # "sig_node" (signature node). The "name" received here is expected to
+ # be unique and will be the value returned by a corresponding call to
+ # handle_signature().
+
+ targetid = '%s-instruction' % (name)
+ sig_node['ids'].append(targetid)
+ self.state.document.note_explicit_target(sig_node)
+ self.env.domaindata[self.domain]['instruction'][targetid] = self.env.docname, sig
+
+class GuacDomain(Domain):
+ """
+ Sphinx domain specific to the Guacamole protocol, containing a single
+ directive ("guac:instruction") that represents a single Guacamole
+ instruction.
+ """
+
+ # Each of the attributes and functions below are defined and inherited from
+ # the superclass (Domain).
+
+ name = 'guac'
+ label = 'Guacamole Protocol'
+
+ initial_data = {
+
+ # Mapping of instruction name to (docname, title) tuples, where docname
+ # is the name of the document containing the object and title is opcode
+ # of the instruction being documented
+ 'instruction' : {}
+
+ }
+
+ object_types = {
+ 'instruction' : ObjType('instruction')
+ }
+
+ directives = {
+ 'instruction' : GuacInstruction
+ }
+
+ roles = {
+ 'instruction' : XRefRole()
+ }
+
+ dangling_warnings = {
+ 'instruction' : "No documentation found for Guacamole instruction '%(target)s'"
+ }
+
+ def clear_doc(self, docname):
+
+ # Clear all cached data associated with the given document
+ instruction_list = self.data['instruction']
+ for inst, doc in list(instruction_list.items()):
+ if doc == docname:
+ del instruction_list[inst]
+
+ def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
+
+ # Do not attempt to satisfy crossreferences for object types not
+ # handled by this domain
+ if typ not in self.data:
+ return None
+
+ # Do not attempt to satisfy crossreferences for unknown objects
+ data = self.data[typ]
+ if target not in data:
+ return None
+
+ # Retrieve target document and title from stored data
+ (todocname, title) = data[target]
+
+ return make_refnode(builder, fromdocname, todocname, target, contnode, title)
+
+ def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
+
+ resolved = []
+
+ # Search ALL types to enumerate all possible resolutions
+ for typ in self.object_types:
+
+ data = self.data[typ]
+
+ # If the target exists within the set of known objects of the
+ # current type, generate the required ('domain:role', node) tuple
+ if target in data:
+ (todocname, title) = data[target]
+ resolved.append((
+ self.name + ':' + typ,
+ make_refnode(builder, fromdocname, todocname, target, contnode, title)
+ ))
+
+ return resolved
+
+def setup(app: Sphinx):
+ app.add_domain(GuacDomain)
+
diff --git a/src/fonts/deja-vu-sans-mono/DejaVuSansMono-Bold.ttf b/src/fonts/deja-vu-sans-mono/DejaVuSansMono-Bold.ttf
deleted file mode 100644
index 0d538bc..0000000
--- a/src/fonts/deja-vu-sans-mono/DejaVuSansMono-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/src/fonts/deja-vu-sans-mono/DejaVuSansMono-BoldOblique.ttf b/src/fonts/deja-vu-sans-mono/DejaVuSansMono-BoldOblique.ttf
deleted file mode 100644
index bcc5149..0000000
--- a/src/fonts/deja-vu-sans-mono/DejaVuSansMono-BoldOblique.ttf
+++ /dev/null
Binary files differ
diff --git a/src/fonts/deja-vu-sans-mono/DejaVuSansMono-Oblique.ttf b/src/fonts/deja-vu-sans-mono/DejaVuSansMono-Oblique.ttf
deleted file mode 100644
index f003257..0000000
--- a/src/fonts/deja-vu-sans-mono/DejaVuSansMono-Oblique.ttf
+++ /dev/null
Binary files differ
diff --git a/src/fonts/deja-vu-sans-mono/DejaVuSansMono.ttf b/src/fonts/deja-vu-sans-mono/DejaVuSansMono.ttf
deleted file mode 100644
index b16a882..0000000
--- a/src/fonts/deja-vu-sans-mono/DejaVuSansMono.ttf
+++ /dev/null
Binary files differ
diff --git a/src/fonts/deja-vu-sans-mono/LICENSE b/src/fonts/deja-vu-sans-mono/LICENSE
deleted file mode 100644
index e2fca55..0000000
--- a/src/fonts/deja-vu-sans-mono/LICENSE
+++ /dev/null
@@ -1,107 +0,0 @@
--------------------------------------------------------------------------------
- License
--------------------------------------------------------------------------------
-
-Fonts are copyright Bitstream. DejaVu changes are in public domain. Glyphs
-imported from Arev fonts are copyright Tavmjung Bah.
-
-See:
-
- http://dejavu-fonts.org/wiki/License
- https://www.gnome.org/fonts/
-
--------------------------------------------------------------------------------
- Bitstream Vera Fonts Copyright
--------------------------------------------------------------------------------
-
-Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a
-trademark of Bitstream, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-the fonts accompanying this license ("Fonts") and associated documentation
-files (the "Font Software"), to reproduce and distribute the Font Software,
-including without limitation the rights to use, copy, merge, publish,
-distribute, and/or sell copies of the Font Software, and to permit persons to
-whom the Font Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright and trademark notices and this permission notice shall be
-included in all copies of one or more of the Font Software typefaces.
-
-The Font Software may be modified, altered, or added to, and in particular the
-designs of glyphs or characters in the Fonts may be modified and additional
-glyphs or characters may be added to the Fonts, only if the fonts are renamed
-to names not containing either the words "Bitstream" or the word "Vera".
-
-This License becomes null and void to the extent applicable to Fonts or Font
-Software that has been modified and is distributed under the "Bitstream Vera"
-names.
-
-The Font Software may be sold as part of a larger software package but no copy
-of one or more of the Font Software typefaces may be sold by itself.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
-TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION
-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
-SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO
-USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
-
-Except as contained in this notice, the names of Gnome, the Gnome Foundation,
-and Bitstream Inc., shall not be used in advertising or otherwise to promote
-the sale, use or other dealings in this Font Software without prior written
-authorization from the Gnome Foundation or Bitstream Inc., respectively. For
-further information, contact: fonts at gnome dot org.
-
-
--------------------------------------------------------------------------------
- Modifications to the Bitstream Vera fonts (Arev Fonts Copyright)
--------------------------------------------------------------------------------
-
-Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the fonts accompanying this license ("Fonts") and
-associated documentation files (the "Font Software"), to reproduce
-and distribute the modifications to the Bitstream Vera Font Software,
-including without limitation the rights to use, copy, merge, publish,
-distribute, and/or sell copies of the Font Software, and to permit
-persons to whom the Font Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright and trademark notices and this permission notice
-shall be included in all copies of one or more of the Font Software
-typefaces.
-
-The Font Software may be modified, altered, or added to, and in
-particular the designs of glyphs or characters in the Fonts may be
-modified and additional glyphs or characters may be added to the
-Fonts, only if the fonts are renamed to names not containing either
-the words "Tavmjong Bah" or the word "Arev".
-
-This License becomes null and void to the extent applicable to Fonts
-or Font Software that has been modified and is distributed under the
-"Tavmjong Bah Arev" names.
-
-The Font Software may be sold as part of a larger software package but
-no copy of one or more of the Font Software typefaces may be sold by
-itself.
-
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
-TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
-
-Except as contained in this notice, the name of Tavmjong Bah shall not
-be used in advertising or otherwise to promote the sale, use or other
-dealings in this Font Software without prior written authorization
-from Tavmjong Bah. For further information, contact: tavmjong @ free
-. fr.
-
diff --git a/src/fonts/nimbus-roman-no-9-l/LICENSE b/src/fonts/nimbus-roman-no-9-l/LICENSE
deleted file mode 100644
index 2244313..0000000
--- a/src/fonts/nimbus-roman-no-9-l/LICENSE
+++ /dev/null
@@ -1,416 +0,0 @@
-The LaTeX Project Public License
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-LPPL Version 1.3c 2008-05-04
-
-Copyright 1999 2002-2008 LaTeX3 Project
- Everyone is allowed to distribute verbatim copies of this
- license document, but modification of it is not allowed.
-
-
-PREAMBLE
-========
-
-The LaTeX Project Public License (LPPL) is the primary license under
-which the LaTeX kernel and the base LaTeX packages are distributed.
-
-You may use this license for any work of which you hold the copyright
-and which you wish to distribute. This license may be particularly
-suitable if your work is TeX-related (such as a LaTeX package), but
-it is written in such a way that you can use it even if your work is
-unrelated to TeX.
-
-The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE',
-below, gives instructions, examples, and recommendations for authors
-who are considering distributing their works under this license.
-
-This license gives conditions under which a work may be distributed
-and modified, as well as conditions under which modified versions of
-that work may be distributed.
-
-We, the LaTeX3 Project, believe that the conditions below give you
-the freedom to make and distribute modified versions of your work
-that conform with whatever technical specifications you wish while
-maintaining the availability, integrity, and reliability of
-that work. If you do not see how to achieve your goal while
-meeting these conditions, then read the document `cfgguide.tex'
-and `modguide.tex' in the base LaTeX distribution for suggestions.
-
-
-DEFINITIONS
-===========
-
-In this license document the following terms are used:
-
- `Work'
- Any work being distributed under this License.
-
- `Derived Work'
- Any work that under any applicable law is derived from the Work.
-
- `Modification'
- Any procedure that produces a Derived Work under any applicable
- law -- for example, the production of a file containing an
- original file associated with the Work or a significant portion of
- such a file, either verbatim or with modifications and/or
- translated into another language.
-
- `Modify'
- To apply any procedure that produces a Derived Work under any
- applicable law.
-
- `Distribution'
- Making copies of the Work available from one person to another, in
- whole or in part. Distribution includes (but is not limited to)
- making any electronic components of the Work accessible by
- file transfer protocols such as FTP or HTTP or by shared file
- systems such as Sun's Network File System (NFS).
-
- `Compiled Work'
- A version of the Work that has been processed into a form where it
- is directly usable on a computer system. This processing may
- include using installation facilities provided by the Work,
- transformations of the Work, copying of components of the Work, or
- other activities. Note that modification of any installation
- facilities provided by the Work constitutes modification of the Work.
-
- `Current Maintainer'
- A person or persons nominated as such within the Work. If there is
- no such explicit nomination then it is the `Copyright Holder' under
- any applicable law.
-
- `Base Interpreter'
- A program or process that is normally needed for running or
- interpreting a part or the whole of the Work.
-
- A Base Interpreter may depend on external components but these
- are not considered part of the Base Interpreter provided that each
- external component clearly identifies itself whenever it is used
- interactively. Unless explicitly specified when applying the
- license to the Work, the only applicable Base Interpreter is a
- `LaTeX-Format' or in the case of files belonging to the
- `LaTeX-format' a program implementing the `TeX language'.
-
-
-
-CONDITIONS ON DISTRIBUTION AND MODIFICATION
-===========================================
-
-1. Activities other than distribution and/or modification of the Work
-are not covered by this license; they are outside its scope. In
-particular, the act of running the Work is not restricted and no
-requirements are made concerning any offers of support for the Work.
-
-2. You may distribute a complete, unmodified copy of the Work as you
-received it. Distribution of only part of the Work is considered
-modification of the Work, and no right to distribute such a Derived
-Work may be assumed under the terms of this clause.
-
-3. You may distribute a Compiled Work that has been generated from a
-complete, unmodified copy of the Work as distributed under Clause 2
-above, as long as that Compiled Work is distributed in such a way that
-the recipients may install the Compiled Work on their system exactly
-as it would have been installed if they generated a Compiled Work
-directly from the Work.
-
-4. If you are the Current Maintainer of the Work, you may, without
-restriction, modify the Work, thus creating a Derived Work. You may
-also distribute the Derived Work without restriction, including
-Compiled Works generated from the Derived Work. Derived Works
-distributed in this manner by the Current Maintainer are considered to
-be updated versions of the Work.
-
-5. If you are not the Current Maintainer of the Work, you may modify
-your copy of the Work, thus creating a Derived Work based on the Work,
-and compile this Derived Work, thus creating a Compiled Work based on
-the Derived Work.
-
-6. If you are not the Current Maintainer of the Work, you may
-distribute a Derived Work provided the following conditions are met
-for every component of the Work unless that component clearly states
-in the copyright notice that it is exempt from that condition. Only
-the Current Maintainer is allowed to add such statements of exemption
-to a component of the Work.
-
- a. If a component of this Derived Work can be a direct replacement
- for a component of the Work when that component is used with the
- Base Interpreter, then, wherever this component of the Work
- identifies itself to the user when used interactively with that
- Base Interpreter, the replacement component of this Derived Work
- clearly and unambiguously identifies itself as a modified version
- of this component to the user when used interactively with that
- Base Interpreter.
-
- b. Every component of the Derived Work contains prominent notices
- detailing the nature of the changes to that component, or a
- prominent reference to another file that is distributed as part
- of the Derived Work and that contains a complete and accurate log
- of the changes.
-
- c. No information in the Derived Work implies that any persons,
- including (but not limited to) the authors of the original version
- of the Work, provide any support, including (but not limited to)
- the reporting and handling of errors, to recipients of the
- Derived Work unless those persons have stated explicitly that
- they do provide such support for the Derived Work.
-
- d. You distribute at least one of the following with the Derived Work:
-
- 1. A complete, unmodified copy of the Work;
- if your distribution of a modified component is made by
- offering access to copy the modified component from a
- designated place, then offering equivalent access to copy
- the Work from the same or some similar place meets this
- condition, even though third parties are not compelled to
- copy the Work along with the modified component;
-
- 2. Information that is sufficient to obtain a complete,
- unmodified copy of the Work.
-
-7. If you are not the Current Maintainer of the Work, you may
-distribute a Compiled Work generated from a Derived Work, as long as
-the Derived Work is distributed to all recipients of the Compiled
-Work, and as long as the conditions of Clause 6, above, are met with
-regard to the Derived Work.
-
-8. The conditions above are not intended to prohibit, and hence do not
-apply to, the modification, by any method, of any component so that it
-becomes identical to an updated version of that component of the Work as
-it is distributed by the Current Maintainer under Clause 4, above.
-
-9. Distribution of the Work or any Derived Work in an alternative
-format, where the Work or that Derived Work (in whole or in part) is
-then produced by applying some process to that format, does not relax or
-nullify any sections of this license as they pertain to the results of
-applying that process.
-
-10. a. A Derived Work may be distributed under a different license
- provided that license itself honors the conditions listed in
- Clause 6 above, in regard to the Work, though it does not have
- to honor the rest of the conditions in this license.
-
- b. If a Derived Work is distributed under a different license, that
- Derived Work must provide sufficient documentation as part of
- itself to allow each recipient of that Derived Work to honor the
- restrictions in Clause 6 above, concerning changes from the Work.
-
-11. This license places no restrictions on works that are unrelated to
-the Work, nor does this license place any restrictions on aggregating
-such works with the Work by any means.
-
-12. Nothing in this license is intended to, or may be used to, prevent
-complete compliance by all parties with all applicable laws.
-
-
-NO WARRANTY
-===========
-
-There is no warranty for the Work. Except when otherwise stated in
-writing, the Copyright Holder provides the Work `as is', without
-warranty of any kind, either expressed or implied, including, but not
-limited to, the implied warranties of merchantability and fitness for a
-particular purpose. The entire risk as to the quality and performance
-of the Work is with you. Should the Work prove defective, you assume
-the cost of all necessary servicing, repair, or correction.
-
-In no event unless required by applicable law or agreed to in writing
-will The Copyright Holder, or any author named in the components of the
-Work, or any other party who may distribute and/or modify the Work as
-permitted above, be liable to you for damages, including any general,
-special, incidental or consequential damages arising out of any use of
-the Work or out of inability to use the Work (including, but not limited
-to, loss of data, data being rendered inaccurate, or losses sustained by
-anyone as a result of any failure of the Work to operate with any other
-programs), even if the Copyright Holder or said author or said other
-party has been advised of the possibility of such damages.
-
-
-MAINTENANCE OF THE WORK
-=======================
-
-The Work has the status `author-maintained' if the Copyright Holder
-explicitly and prominently states near the primary copyright notice in
-the Work that the Work can only be maintained by the Copyright Holder
-or simply that it is `author-maintained'.
-
-The Work has the status `maintained' if there is a Current Maintainer
-who has indicated in the Work that they are willing to receive error
-reports for the Work (for example, by supplying a valid e-mail
-address). It is not required for the Current Maintainer to acknowledge
-or act upon these error reports.
-
-The Work changes from status `maintained' to `unmaintained' if there
-is no Current Maintainer, or the person stated to be Current
-Maintainer of the work cannot be reached through the indicated means
-of communication for a period of six months, and there are no other
-significant signs of active maintenance.
-
-You can become the Current Maintainer of the Work by agreement with
-any existing Current Maintainer to take over this role.
-
-If the Work is unmaintained, you can become the Current Maintainer of
-the Work through the following steps:
-
- 1. Make a reasonable attempt to trace the Current Maintainer (and
- the Copyright Holder, if the two differ) through the means of
- an Internet or similar search.
-
- 2. If this search is successful, then enquire whether the Work
- is still maintained.
-
- a. If it is being maintained, then ask the Current Maintainer
- to update their communication data within one month.
-
- b. If the search is unsuccessful or no action to resume active
- maintenance is taken by the Current Maintainer, then announce
- within the pertinent community your intention to take over
- maintenance. (If the Work is a LaTeX work, this could be
- done, for example, by posting to comp.text.tex.)
-
- 3a. If the Current Maintainer is reachable and agrees to pass
- maintenance of the Work to you, then this takes effect
- immediately upon announcement.
-
- b. If the Current Maintainer is not reachable and the Copyright
- Holder agrees that maintenance of the Work be passed to you,
- then this takes effect immediately upon announcement.
-
- 4. If you make an `intention announcement' as described in 2b. above
- and after three months your intention is challenged neither by
- the Current Maintainer nor by the Copyright Holder nor by other
- people, then you may arrange for the Work to be changed so as
- to name you as the (new) Current Maintainer.
-
- 5. If the previously unreachable Current Maintainer becomes
- reachable once more within three months of a change completed
- under the terms of 3b) or 4), then that Current Maintainer must
- become or remain the Current Maintainer upon request provided
- they then update their communication data within one month.
-
-A change in the Current Maintainer does not, of itself, alter the fact
-that the Work is distributed under the LPPL license.
-
-If you become the Current Maintainer of the Work, you should
-immediately provide, within the Work, a prominent and unambiguous
-statement of your status as Current Maintainer. You should also
-announce your new status to the same pertinent community as
-in 2b) above.
-
-
-WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE
-======================================================
-
-This section contains important instructions, examples, and
-recommendations for authors who are considering distributing their
-works under this license. These authors are addressed as `you' in
-this section.
-
-Choosing This License or Another License
-----------------------------------------
-
-If for any part of your work you want or need to use *distribution*
-conditions that differ significantly from those in this license, then
-do not refer to this license anywhere in your work but, instead,
-distribute your work under a different license. You may use the text
-of this license as a model for your own license, but your license
-should not refer to the LPPL or otherwise give the impression that
-your work is distributed under the LPPL.
-
-The document `modguide.tex' in the base LaTeX distribution explains
-the motivation behind the conditions of this license. It explains,
-for example, why distributing LaTeX under the GNU General Public
-License (GPL) was considered inappropriate. Even if your work is
-unrelated to LaTeX, the discussion in `modguide.tex' may still be
-relevant, and authors intending to distribute their works under any
-license are encouraged to read it.
-
-A Recommendation on Modification Without Distribution
------------------------------------------------------
-
-It is wise never to modify a component of the Work, even for your own
-personal use, without also meeting the above conditions for
-distributing the modified component. While you might intend that such
-modifications will never be distributed, often this will happen by
-accident -- you may forget that you have modified that component; or
-it may not occur to you when allowing others to access the modified
-version that you are thus distributing it and violating the conditions
-of this license in ways that could have legal implications and, worse,
-cause problems for the community. It is therefore usually in your
-best interest to keep your copy of the Work identical with the public
-one. Many works provide ways to control the behavior of that work
-without altering any of its licensed components.
-
-How to Use This License
------------------------
-
-To use this license, place in each of the components of your work both
-an explicit copyright notice including your name and the year the work
-was authored and/or last substantially modified. Include also a
-statement that the distribution and/or modification of that
-component is constrained by the conditions in this license.
-
-Here is an example of such a notice and statement:
-
- %% pig.dtx
- %% Copyright 2005 M. Y. Name
- %
- % This work may be distributed and/or modified under the
- % conditions of the LaTeX Project Public License, either version 1.3
- % of this license or (at your option) any later version.
- % The latest version of this license is in
- % http://www.latex-project.org/lppl.txt
- % and version 1.3 or later is part of all distributions of LaTeX
- % version 2005/12/01 or later.
- %
- % This work has the LPPL maintenance status `maintained'.
- %
- % The Current Maintainer of this work is M. Y. Name.
- %
- % This work consists of the files pig.dtx and pig.ins
- % and the derived file pig.sty.
-
-Given such a notice and statement in a file, the conditions
-given in this license document would apply, with the `Work' referring
-to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being
-generated from `pig.dtx' using `pig.ins'), the `Base Interpreter'
-referring to any `LaTeX-Format', and both `Copyright Holder' and
-`Current Maintainer' referring to the person `M. Y. Name'.
-
-If you do not want the Maintenance section of LPPL to apply to your
-Work, change `maintained' above into `author-maintained'.
-However, we recommend that you use `maintained', as the Maintenance
-section was added in order to ensure that your Work remains useful to
-the community even when you can no longer maintain and support it
-yourself.
-
-Derived Works That Are Not Replacements
----------------------------------------
-
-Several clauses of the LPPL specify means to provide reliability and
-stability for the user community. They therefore concern themselves
-with the case that a Derived Work is intended to be used as a
-(compatible or incompatible) replacement of the original Work. If
-this is not the case (e.g., if a few lines of code are reused for a
-completely different task), then clauses 6b and 6d shall not apply.
-
-
-Important Recommendations
--------------------------
-
- Defining What Constitutes the Work
-
- The LPPL requires that distributions of the Work contain all the
- files of the Work. It is therefore important that you provide a
- way for the licensee to determine which files constitute the Work.
- This could, for example, be achieved by explicitly listing all the
- files of the Work near the copyright notice of each file or by
- using a line such as:
-
- % This work consists of all files listed in manifest.txt.
-
- in that place. In the absence of an unequivocal list it might be
- impossible for the licensee to determine what is considered by you
- to comprise the Work and, in such a case, the licensee would be
- entitled to make reasonable conjectures as to which files comprise
- the Work.
-
diff --git a/src/fonts/nimbus-roman-no-9-l/n021003l.afm b/src/fonts/nimbus-roman-no-9-l/n021003l.afm
deleted file mode 100644
index bc68a4b..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021003l.afm
+++ /dev/null
@@ -1,1572 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 13:14:49 2007
-FontName NimbusRomNo9L-Regu
-FullName Nimbus Roman No9 L Regular
-FamilyName Nimbus Roman No9 L
-Weight Regular
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle 0
-IsFixedPitch false
-UnderlinePosition -100
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -168 -281 1031 924
-CapHeight 662
-XHeight 450
-Ascender 683
-Descender -217
-StartCharMetrics 562
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 130 -9 237 676 ;
-C 34 ; WX 408 ; N quotedbl ; B 77 431 331 676 ;
-C 35 ; WX 500 ; N numbersign ; B 5 0 496 662 ;
-C 36 ; WX 500 ; N dollar ; B 44 -87 457 727 ;
-C 37 ; WX 833 ; N percent ; B 61 -13 772 676 ;
-C 38 ; WX 778 ; N ampersand ; B 42 -13 750 676 ;
-C 39 ; WX 333 ; N quoteright ; B 79 433 218 676 ;
-C 40 ; WX 333 ; N parenleft ; B 48 -177 304 676 ;
-C 41 ; WX 333 ; N parenright ; B 29 -177 285 676 ;
-C 42 ; WX 500 ; N asterisk ; B 69 265 432 676 ;
-C 43 ; WX 564 ; N plus ; B 30 0 534 506 ;
-C 44 ; WX 250 ; N comma ; B 56 -141 195 102 ;
-C 45 ; WX 333 ; N hyphen ; B 39 194 285 257 ;
-C 46 ; WX 250 ; N period ; B 70 -11 181 100 ;
-C 47 ; WX 278 ; N slash ; B -9 -14 287 676 ;
-C 48 ; WX 500 ; N zero ; B 24 -14 476 676 ;
-C 49 ; WX 500 ; N one ; B 111 0 394 676 ;
-C 50 ; WX 500 ; N two ; B 30 0 475 676 ;
-C 51 ; WX 500 ; N three ; B 43 -14 432 676 ;
-C 52 ; WX 500 ; N four ; B 12 0 472 676 ;
-C 53 ; WX 500 ; N five ; B 32 -14 438 688 ;
-C 54 ; WX 500 ; N six ; B 34 -14 468 684 ;
-C 55 ; WX 500 ; N seven ; B 20 -8 449 662 ;
-C 56 ; WX 500 ; N eight ; B 56 -14 445 676 ;
-C 57 ; WX 500 ; N nine ; B 30 -22 459 676 ;
-C 58 ; WX 278 ; N colon ; B 81 -11 192 459 ;
-C 59 ; WX 278 ; N semicolon ; B 80 -141 219 459 ;
-C 60 ; WX 564 ; N less ; B 28 -10 536 516 ;
-C 61 ; WX 564 ; N equal ; B 30 120 534 386 ;
-C 62 ; WX 564 ; N greater ; B 28 -10 536 516 ;
-C 63 ; WX 444 ; N question ; B 68 -8 414 676 ;
-C 64 ; WX 921 ; N at ; B 116 -14 809 676 ;
-C 65 ; WX 722 ; N A ; B 15 0 706 674 ;
-C 66 ; WX 667 ; N B ; B 17 0 593 662 ;
-C 67 ; WX 667 ; N C ; B 28 -14 633 676 ;
-C 68 ; WX 722 ; N D ; B 16 0 685 662 ;
-C 69 ; WX 611 ; N E ; B 12 0 597 662 ;
-C 70 ; WX 556 ; N F ; B 12 0 546 662 ;
-C 71 ; WX 722 ; N G ; B 32 -14 709 676 ;
-C 72 ; WX 722 ; N H ; B 19 0 702 662 ;
-C 73 ; WX 333 ; N I ; B 18 0 315 662 ; L J IJ ;
-C 74 ; WX 389 ; N J ; B 10 -14 370 662 ;
-C 75 ; WX 722 ; N K ; B 34 0 723 662 ;
-C 76 ; WX 611 ; N L ; B 12 0 598 662 ; L periodcentered Ldot ;
-C 77 ; WX 889 ; N M ; B 12 0 863 662 ;
-C 78 ; WX 722 ; N N ; B 12 -11 707 662 ; L o afii61352 ;
-C 79 ; WX 722 ; N O ; B 34 -14 688 676 ;
-C 80 ; WX 556 ; N P ; B 16 0 542 662 ;
-C 81 ; WX 722 ; N Q ; B 34 -178 701 676 ;
-C 82 ; WX 667 ; N R ; B 17 0 659 662 ;
-C 83 ; WX 556 ; N S ; B 42 -14 491 676 ;
-C 84 ; WX 611 ; N T ; B 17 0 593 662 ; L M trademark ;
-C 85 ; WX 722 ; N U ; B 14 -14 705 662 ;
-C 86 ; WX 722 ; N V ; B 16 -11 697 662 ;
-C 87 ; WX 944 ; N W ; B 5 -11 932 662 ;
-C 88 ; WX 722 ; N X ; B 10 0 704 662 ;
-C 89 ; WX 722 ; N Y ; B 22 0 703 662 ;
-C 90 ; WX 611 ; N Z ; B 9 0 597 662 ;
-C 91 ; WX 333 ; N bracketleft ; B 88 -156 299 662 ;
-C 92 ; WX 278 ; N backslash ; B -9 -14 287 676 ;
-C 93 ; WX 333 ; N bracketright ; B 34 -156 245 662 ;
-C 94 ; WX 469 ; N asciicircum ; B 24 297 446 662 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 115 433 254 676 ;
-C 97 ; WX 444 ; N a ; B 37 -10 442 460 ;
-C 98 ; WX 500 ; N b ; B 3 -10 468 683 ;
-C 99 ; WX 444 ; N c ; B 25 -10 412 460 ;
-C 100 ; WX 500 ; N d ; B 27 -10 491 683 ;
-C 101 ; WX 444 ; N e ; B 25 -10 424 460 ;
-C 102 ; WX 333 ; N f ; B 20 0 383 683 ; L l fl ; L i fi ;
-C 103 ; WX 500 ; N g ; B 28 -218 470 460 ;
-C 104 ; WX 500 ; N h ; B 9 0 487 683 ;
-C 105 ; WX 278 ; N i ; B 16 0 253 683 ; L j ij ;
-C 106 ; WX 278 ; N j ; B -70 -218 194 683 ;
-C 107 ; WX 500 ; N k ; B 7 0 505 683 ;
-C 108 ; WX 278 ; N l ; B 19 0 257 683 ; L periodcentered ldot ;
-C 109 ; WX 778 ; N m ; B 16 0 775 460 ;
-C 110 ; WX 500 ; N n ; B 16 0 485 460 ;
-C 111 ; WX 500 ; N o ; B 29 -10 470 460 ;
-C 112 ; WX 500 ; N p ; B 5 -217 470 460 ;
-C 113 ; WX 500 ; N q ; B 24 -217 488 461 ;
-C 114 ; WX 333 ; N r ; B 5 0 335 460 ;
-C 115 ; WX 389 ; N s ; B 51 -10 348 459 ;
-C 116 ; WX 278 ; N t ; B 13 -10 279 579 ;
-C 117 ; WX 500 ; N u ; B 9 -10 479 450 ;
-C 118 ; WX 500 ; N v ; B 19 -14 477 450 ;
-C 119 ; WX 722 ; N w ; B 21 -14 694 450 ;
-C 120 ; WX 500 ; N x ; B 17 0 479 450 ;
-C 121 ; WX 500 ; N y ; B 14 -218 475 450 ;
-C 122 ; WX 444 ; N z ; B 27 0 418 450 ;
-C 123 ; WX 480 ; N braceleft ; B 100 -181 350 680 ;
-C 124 ; WX 200 ; N bar ; B 67 -14 133 676 ;
-C 125 ; WX 480 ; N braceright ; B 130 -181 380 680 ;
-C 126 ; WX 541 ; N asciitilde ; B 40 186 502 320 ;
-C 161 ; WX 333 ; N exclamdown ; B 97 -218 204 469 ;
-C 162 ; WX 500 ; N cent ; B 53 -138 448 579 ;
-C 163 ; WX 500 ; N sterling ; B 12 -8 490 676 ;
-C 164 ; WX 167 ; N fraction ; B -168 -14 331 676 ;
-C 165 ; WX 500 ; N yen ; B -53 0 512 662 ;
-C 166 ; WX 500 ; N florin ; B 7 -189 490 676 ;
-C 167 ; WX 500 ; N section ; B 70 -148 426 676 ;
-C 168 ; WX 500 ; N currency ; B -22 58 522 602 ;
-C 169 ; WX 180 ; N quotesingle ; B 48 431 133 676 ;
-C 170 ; WX 444 ; N quotedblleft ; B 43 433 414 676 ;
-C 171 ; WX 500 ; N guillemotleft ; B 42 33 456 416 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 63 33 285 416 ;
-C 173 ; WX 333 ; N guilsinglright ; B 48 33 270 416 ;
-C 174 ; WX 556 ; N fi ; B 31 0 521 683 ;
-C 175 ; WX 556 ; N fl ; B 32 0 521 683 ;
-C 177 ; WX 500 ; N endash ; B 0 201 500 250 ;
-C 178 ; WX 500 ; N dagger ; B 59 -149 443 676 ;
-C 179 ; WX 500 ; N daggerdbl ; B 58 -153 442 676 ;
-C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ;
-C 182 ; WX 453 ; N paragraph ; B -22 -154 450 662 ;
-C 183 ; WX 350 ; N bullet ; B 40 196 310 466 ;
-C 184 ; WX 333 ; N quotesinglbase ; B 79 -141 218 102 ;
-C 185 ; WX 444 ; N quotedblbase ; B 45 -141 416 102 ;
-C 186 ; WX 444 ; N quotedblright ; B 30 433 401 676 ;
-C 187 ; WX 500 ; N guillemotright ; B 44 33 458 416 ;
-C 188 ; WX 1000 ; N ellipsis ; B 111 -11 888 100 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 706 ;
-C 191 ; WX 444 ; N questiondown ; B 30 -218 376 468 ;
-C 193 ; WX 333 ; N grave ; B 19 507 242 678 ;
-C 194 ; WX 333 ; N acute ; B 93 507 317 678 ;
-C 195 ; WX 333 ; N circumflex ; B 11 507 322 674 ;
-C 196 ; WX 333 ; N tilde ; B 1 532 331 638 ;
-C 197 ; WX 333 ; N macron ; B 11 547 322 601 ;
-C 198 ; WX 333 ; N breve ; B 26 507 307 664 ;
-C 199 ; WX 333 ; N dotaccent ; B 118 523 217 622 ;
-C 200 ; WX 333 ; N dieresis ; B 18 523 316 622 ;
-C 202 ; WX 333 ; N ring ; B 67 512 266 711 ;
-C 203 ; WX 333 ; N cedilla ; B 52 -215 261 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B -3 507 377 678 ;
-C 206 ; WX 333 ; N ogonek ; B 64 -165 249 0 ;
-C 207 ; WX 333 ; N caron ; B 11 507 322 674 ;
-C 208 ; WX 1000 ; N emdash ; B 0 201 1000 250 ;
-C 225 ; WX 889 ; N AE ; B 0 0 863 662 ;
-C 227 ; WX 276 ; N ordfeminine ; B 4 394 270 676 ;
-C 232 ; WX 611 ; N Lslash ; B 12 0 598 662 ;
-C 233 ; WX 722 ; N Oslash ; B 34 -80 688 734 ;
-C 234 ; WX 889 ; N OE ; B 30 -6 885 668 ;
-C 235 ; WX 310 ; N ordmasculine ; B 6 394 304 676 ;
-C 241 ; WX 667 ; N ae ; B 38 -10 632 460 ;
-C 245 ; WX 278 ; N dotlessi ; B 16 0 253 460 ;
-C 248 ; WX 278 ; N lslash ; B 19 0 259 683 ;
-C 249 ; WX 500 ; N oslash ; B 29 -112 470 551 ;
-C 250 ; WX 722 ; N oe ; B 30 -10 690 460 ;
-C 251 ; WX 500 ; N germandbls ; B 12 -9 468 683 ;
-C -1 ; WX 722 ; N Adieresis ; B 15 0 706 834 ;
-C -1 ; WX 722 ; N Aacute ; B 15 0 706 890 ;
-C -1 ; WX 722 ; N Agrave ; B 15 0 706 890 ;
-C -1 ; WX 722 ; N Acircumflex ; B 15 0 706 886 ;
-C -1 ; WX 722 ; N Abreve ; B 15 0 706 876 ;
-C -1 ; WX 722 ; N Atilde ; B 15 0 706 850 ;
-C -1 ; WX 722 ; N Aring ; B 15 0 706 915 ;
-C -1 ; WX 722 ; N Aogonek ; B 15 -165 786 674 ;
-C -1 ; WX 667 ; N Ccedilla ; B 28 -215 633 676 ;
-C -1 ; WX 667 ; N Cacute ; B 28 -14 633 890 ;
-C -1 ; WX 667 ; N Ccaron ; B 28 -14 633 886 ;
-C -1 ; WX 722 ; N Dcaron ; B 16 0 685 886 ;
-C -1 ; WX 611 ; N Edieresis ; B 12 0 597 834 ;
-C -1 ; WX 611 ; N Eacute ; B 12 0 597 890 ;
-C -1 ; WX 611 ; N Egrave ; B 12 0 597 890 ;
-C -1 ; WX 611 ; N Ecircumflex ; B 12 0 597 886 ;
-C -1 ; WX 611 ; N Ecaron ; B 12 0 597 886 ;
-C -1 ; WX 611 ; N Edotaccent ; B 12 0 597 834 ;
-C -1 ; WX 611 ; N Eogonek ; B 12 -165 611 662 ;
-C -1 ; WX 722 ; N Gbreve ; B 32 -14 709 876 ;
-C -1 ; WX 333 ; N Idieresis ; B 18 0 316 834 ;
-C -1 ; WX 333 ; N Iacute ; B 18 0 317 890 ;
-C -1 ; WX 333 ; N Igrave ; B 18 0 315 890 ;
-C -1 ; WX 333 ; N Icircumflex ; B 11 0 322 886 ;
-C -1 ; WX 333 ; N Idotaccent ; B 18 0 315 834 ;
-C -1 ; WX 611 ; N Lacute ; B 12 0 598 890 ;
-C -1 ; WX 611 ; N Lcaron ; B 12 0 598 676 ;
-C -1 ; WX 722 ; N Nacute ; B 12 -11 707 890 ;
-C -1 ; WX 722 ; N Ncaron ; B 12 -11 707 886 ;
-C -1 ; WX 722 ; N Ntilde ; B 12 -11 707 850 ;
-C -1 ; WX 722 ; N Odieresis ; B 34 -14 688 834 ;
-C -1 ; WX 722 ; N Oacute ; B 34 -14 688 890 ;
-C -1 ; WX 722 ; N Ograve ; B 34 -14 688 890 ;
-C -1 ; WX 722 ; N Ocircumflex ; B 34 -14 688 886 ;
-C -1 ; WX 722 ; N Otilde ; B 34 -14 688 850 ;
-C -1 ; WX 722 ; N Ohungarumlaut ; B 34 -14 688 890 ;
-C -1 ; WX 667 ; N Racute ; B 17 0 659 890 ;
-C -1 ; WX 667 ; N Rcaron ; B 17 0 659 886 ;
-C -1 ; WX 556 ; N Sacute ; B 42 -14 491 890 ;
-C -1 ; WX 556 ; N Scaron ; B 42 -14 491 886 ;
-C -1 ; WX 556 ; N Scedilla ; B 42 -215 491 676 ;
-C -1 ; WX 611 ; N Tcaron ; B 17 0 593 886 ;
-C -1 ; WX 722 ; N Udieresis ; B 14 -14 705 834 ;
-C -1 ; WX 722 ; N Uacute ; B 14 -14 705 890 ;
-C -1 ; WX 722 ; N Ugrave ; B 14 -14 705 890 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 14 -14 705 886 ;
-C -1 ; WX 722 ; N Uring ; B 14 -14 705 923 ;
-C -1 ; WX 722 ; N Uhungarumlaut ; B 14 -14 705 890 ;
-C -1 ; WX 722 ; N Yacute ; B 22 0 703 890 ;
-C -1 ; WX 611 ; N Zacute ; B 9 0 597 890 ;
-C -1 ; WX 611 ; N Zcaron ; B 9 0 597 886 ;
-C -1 ; WX 611 ; N Zdotaccent ; B 9 0 597 834 ;
-C -1 ; WX 722 ; N Amacron ; B 15 0 706 813 ;
-C -1 ; WX 611 ; N Tcommaaccent ; B 17 -281 593 662 ;
-C -1 ; WX 722 ; N Ydieresis ; B 22 0 703 834 ;
-C -1 ; WX 611 ; N Emacron ; B 12 0 597 813 ;
-C -1 ; WX 333 ; N Imacron ; B 11 0 322 813 ;
-C -1 ; WX 333 ; N Iogonek ; B 18 -165 397 662 ;
-C -1 ; WX 722 ; N Kcommaaccent ; B 34 -281 723 662 ;
-C -1 ; WX 611 ; N Lcommaaccent ; B 12 -281 598 662 ;
-C -1 ; WX 722 ; N Ncommaaccent ; B 12 -281 707 662 ;
-C -1 ; WX 722 ; N Omacron ; B 34 -14 688 813 ;
-C -1 ; WX 667 ; N Rcommaaccent ; B 17 -281 659 662 ;
-C -1 ; WX 722 ; N Gcommaaccent ; B 32 -281 709 676 ;
-C -1 ; WX 722 ; N Umacron ; B 14 -14 705 813 ;
-C -1 ; WX 722 ; N Uogonek ; B 14 -165 705 662 ;
-C -1 ; WX 444 ; N adieresis ; B 37 -10 442 622 ;
-C -1 ; WX 444 ; N aacute ; B 37 -10 442 678 ;
-C -1 ; WX 444 ; N agrave ; B 37 -10 442 678 ;
-C -1 ; WX 444 ; N acircumflex ; B 37 -10 442 674 ;
-C -1 ; WX 444 ; N abreve ; B 37 -10 442 664 ;
-C -1 ; WX 444 ; N atilde ; B 37 -10 442 638 ;
-C -1 ; WX 444 ; N aring ; B 37 -10 442 721 ;
-C -1 ; WX 444 ; N aogonek ; B 37 -165 444 460 ;
-C -1 ; WX 444 ; N cacute ; B 25 -10 412 678 ;
-C -1 ; WX 444 ; N ccaron ; B 25 -10 412 674 ;
-C -1 ; WX 444 ; N ccedilla ; B 25 -215 412 460 ;
-C -1 ; WX 600 ; N dcaron ; B 27 -10 599 683 ;
-C -1 ; WX 444 ; N edieresis ; B 25 -10 424 622 ;
-C -1 ; WX 444 ; N eacute ; B 25 -10 424 678 ;
-C -1 ; WX 444 ; N egrave ; B 25 -10 424 678 ;
-C -1 ; WX 444 ; N ecircumflex ; B 25 -10 424 674 ;
-C -1 ; WX 444 ; N ecaron ; B 25 -10 424 674 ;
-C -1 ; WX 444 ; N edotaccent ; B 25 -10 424 622 ;
-C -1 ; WX 444 ; N eogonek ; B 25 -165 424 460 ;
-C -1 ; WX 500 ; N gbreve ; B 28 -218 470 664 ;
-C -1 ; WX 278 ; N idieresis ; B 11 0 269 622 ;
-C -1 ; WX 278 ; N iacute ; B 16 0 290 678 ;
-C -1 ; WX 278 ; N igrave ; B -8 0 253 678 ;
-C -1 ; WX 278 ; N icircumflex ; B -16 0 295 674 ;
-C -1 ; WX 278 ; N lacute ; B 19 0 290 890 ;
-C -1 ; WX 348 ; N lcaron ; B 19 0 348 683 ;
-C -1 ; WX 500 ; N nacute ; B 16 0 485 678 ;
-C -1 ; WX 500 ; N ncaron ; B 16 0 485 674 ;
-C -1 ; WX 500 ; N ntilde ; B 16 0 485 638 ;
-C -1 ; WX 500 ; N odieresis ; B 29 -10 470 622 ;
-C -1 ; WX 500 ; N oacute ; B 29 -10 470 678 ;
-C -1 ; WX 500 ; N ograve ; B 29 -10 470 678 ;
-C -1 ; WX 500 ; N ocircumflex ; B 29 -10 470 674 ;
-C -1 ; WX 500 ; N otilde ; B 29 -10 470 638 ;
-C -1 ; WX 500 ; N ohungarumlaut ; B 29 -10 470 678 ;
-C -1 ; WX 333 ; N racute ; B 5 0 335 678 ;
-C -1 ; WX 389 ; N sacute ; B 51 -10 365 678 ;
-C -1 ; WX 389 ; N scaron ; B 39 -10 350 674 ;
-C -1 ; WX 389 ; N scommaaccent ; B 51 -281 348 459 ;
-C -1 ; WX 278 ; N tcaron ; B 13 -10 300 676 ;
-C -1 ; WX 500 ; N udieresis ; B 9 -10 479 622 ;
-C -1 ; WX 500 ; N uacute ; B 9 -10 479 678 ;
-C -1 ; WX 500 ; N ugrave ; B 9 -10 479 678 ;
-C -1 ; WX 500 ; N ucircumflex ; B 9 -10 479 674 ;
-C -1 ; WX 500 ; N uring ; B 9 -10 479 711 ;
-C -1 ; WX 500 ; N uhungarumlaut ; B 9 -10 479 678 ;
-C -1 ; WX 500 ; N yacute ; B 14 -218 475 678 ;
-C -1 ; WX 444 ; N zacute ; B 27 0 418 678 ;
-C -1 ; WX 444 ; N zcaron ; B 27 0 418 674 ;
-C -1 ; WX 444 ; N zdotaccent ; B 27 0 418 622 ;
-C -1 ; WX 500 ; N ydieresis ; B 14 -218 475 622 ;
-C -1 ; WX 278 ; N tcommaaccent ; B 13 -281 279 579 ;
-C -1 ; WX 444 ; N amacron ; B 37 -10 442 601 ;
-C -1 ; WX 444 ; N emacron ; B 25 -10 424 601 ;
-C -1 ; WX 278 ; N imacron ; B -16 0 292 601 ;
-C -1 ; WX 500 ; N kcommaaccent ; B 7 -281 505 683 ;
-C -1 ; WX 278 ; N lcommaaccent ; B 19 -281 257 683 ;
-C -1 ; WX 500 ; N ncommaaccent ; B 16 -281 485 460 ;
-C -1 ; WX 500 ; N omacron ; B 29 -10 470 601 ;
-C -1 ; WX 333 ; N rcommaaccent ; B 5 -281 335 460 ;
-C -1 ; WX 500 ; N umacron ; B 9 -10 479 601 ;
-C -1 ; WX 500 ; N uogonek ; B 9 -165 500 450 ;
-C -1 ; WX 333 ; N rcaron ; B 5 0 335 674 ;
-C -1 ; WX 389 ; N scedilla ; B 51 -215 348 459 ;
-C -1 ; WX 500 ; N gcommaaccent ; B 28 -218 470 736 ;
-C -1 ; WX 278 ; N iogonek ; B 16 -165 278 683 ;
-C -1 ; WX 556 ; N Scommaaccent ; B 42 -281 491 676 ;
-C -1 ; WX 722 ; N Eth ; B 16 0 685 662 ;
-C -1 ; WX 722 ; N Dcroat ; B 16 0 685 662 ;
-C -1 ; WX 556 ; N Thorn ; B 16 0 542 662 ;
-C -1 ; WX 500 ; N dcroat ; B 27 -10 500 683 ;
-C -1 ; WX 500 ; N eth ; B 29 -10 471 686 ;
-C -1 ; WX 500 ; N thorn ; B 5 -217 470 683 ;
-C -1 ; WX 500 ; N Euro ; B -16 -14 477 674 ;
-C -1 ; WX 300 ; N onesuperior ; B 57 270 248 676 ;
-C -1 ; WX 300 ; N twosuperior ; B 1 270 296 676 ;
-C -1 ; WX 300 ; N threesuperior ; B 14 262 291 676 ;
-C -1 ; WX 400 ; N degree ; B 57 390 343 676 ;
-C -1 ; WX 564 ; N minus ; B 30 220 534 286 ;
-C -1 ; WX 564 ; N multiply ; B 38 8 527 497 ;
-C -1 ; WX 564 ; N divide ; B 30 -10 534 516 ;
-C -1 ; WX 980 ; N trademark ; B 30 256 957 662 ;
-C -1 ; WX 564 ; N plusminus ; B 30 0 534 568 ;
-C -1 ; WX 750 ; N onehalf ; B 31 -14 746 676 ;
-C -1 ; WX 750 ; N onequarter ; B 37 -14 718 676 ;
-C -1 ; WX 750 ; N threequarters ; B 15 -14 718 676 ;
-C -1 ; WX 333 ; N commaaccent ; B 97 -281 236 -38 ;
-C -1 ; WX 760 ; N copyright ; B 38 -14 722 676 ;
-C -1 ; WX 760 ; N registered ; B 38 -14 722 676 ;
-C -1 ; WX 494 ; N lozenge ; B 18 0 466 740 ;
-C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
-C -1 ; WX 564 ; N notequal ; B 30 -3 534 509 ;
-C -1 ; WX 549 ; N radical ; B -2 -65 526 924 ;
-C -1 ; WX 564 ; N lessequal ; B 28 0 536 628 ;
-C -1 ; WX 564 ; N greaterequal ; B 28 0 536 628 ;
-C -1 ; WX 564 ; N logicalnot ; B 30 108 534 386 ;
-C -1 ; WX 713 ; N summation ; B 14 -123 695 752 ;
-C -1 ; WX 494 ; N partialdiff ; B 26 -10 462 753 ;
-C -1 ; WX 200 ; N brokenbar ; B 67 -14 133 676 ;
-C -1 ; WX 500 ; N mu ; B 36 -218 512 450 ;
-C -1 ; WX 722 ; N afii10017 ; B 15 0 706 674 ;
-C -1 ; WX 650 ; N afii10018 ; B 12 0 588 662 ;
-C -1 ; WX 617 ; N afii10019 ; B 12 0 588 662 ;
-C -1 ; WX 536 ; N afii10020 ; B 12 0 526 662 ;
-C -1 ; WX 672 ; N afii10021 ; B 23 -170 644 662 ;
-C -1 ; WX 611 ; N afii10022 ; B 12 0 597 662 ;
-C -1 ; WX 611 ; N afii10023 ; B 12 0 597 833 ;
-C -1 ; WX 948 ; N afii10024 ; B 11 0 927 668 ;
-C -1 ; WX 508 ; N afii10025 ; B 10 -14 479 675 ;
-C -1 ; WX 715 ; N afii10026 ; B 12 0 695 662 ;
-C -1 ; WX 715 ; N afii10027 ; B 12 0 695 875 ;
-C -1 ; WX 690 ; N afii10028 ; B 12 0 651 668 ;
-C -1 ; WX 702 ; N afii10029 ; B 26 -13 682 662 ;
-C -1 ; WX 883 ; N afii10030 ; B 12 0 863 662 ;
-C -1 ; WX 715 ; N afii10031 ; B 12 0 695 662 ;
-C -1 ; WX 722 ; N afii10032 ; B 34 -14 688 676 ;
-C -1 ; WX 715 ; N afii10033 ; B 12 0 695 662 ;
-C -1 ; WX 552 ; N afii10034 ; B 12 0 538 662 ;
-C -1 ; WX 667 ; N afii10035 ; B 28 -14 633 676 ;
-C -1 ; WX 611 ; N afii10036 ; B 17 0 593 662 ;
-C -1 ; WX 716 ; N afii10037 ; B 20 -12 686 662 ;
-C -1 ; WX 732 ; N afii10038 ; B 10 0 722 662 ;
-C -1 ; WX 722 ; N afii10039 ; B 10 0 704 662 ;
-C -1 ; WX 715 ; N afii10040 ; B 12 -170 683 662 ;
-C -1 ; WX 701 ; N afii10041 ; B 19 0 681 662 ;
-C -1 ; WX 972 ; N afii10042 ; B 12 0 952 662 ;
-C -1 ; WX 974 ; N afii10043 ; B 12 -170 960 662 ;
-C -1 ; WX 710 ; N afii10044 ; B 17 0 696 662 ;
-C -1 ; WX 855 ; N afii10045 ; B 12 0 835 662 ;
-C -1 ; WX 556 ; N afii10046 ; B 16 0 542 662 ;
-C -1 ; WX 649 ; N afii10047 ; B 10 -14 615 676 ;
-C -1 ; WX 958 ; N afii10048 ; B 12 -14 924 676 ;
-C -1 ; WX 679 ; N afii10049 ; B 17 0 659 662 ;
-C -1 ; WX 444 ; N afii10065 ; B 37 -10 442 460 ;
-C -1 ; WX 500 ; N afii10066 ; B 28 -10 470 689 ;
-C -1 ; WX 460 ; N afii10067 ; B 15 0 437 450 ;
-C -1 ; WX 400 ; N afii10068 ; B 15 0 367 450 ;
-C -1 ; WX 518 ; N afii10069 ; B 36 -125 500 450 ;
-C -1 ; WX 444 ; N afii10070 ; B 25 -10 424 460 ;
-C -1 ; WX 444 ; N afii10071 ; B 25 -10 424 622 ;
-C -1 ; WX 669 ; N afii10072 ; B 14 0 656 460 ;
-C -1 ; WX 363 ; N afii10073 ; B 34 -10 353 459 ;
-C -1 ; WX 512 ; N afii10074 ; B 15 0 497 450 ;
-C -1 ; WX 512 ; N afii10075 ; B 15 0 497 667 ;
-C -1 ; WX 508 ; N afii10076 ; B 15 0 498 460 ;
-C -1 ; WX 495 ; N afii10077 ; B 14 -9 480 450 ;
-C -1 ; WX 626 ; N afii10078 ; B 15 -14 611 450 ;
-C -1 ; WX 497 ; N afii10079 ; B 15 0 482 450 ;
-C -1 ; WX 500 ; N afii10080 ; B 29 -10 470 460 ;
-C -1 ; WX 517 ; N afii10081 ; B 15 0 502 450 ;
-C -1 ; WX 500 ; N afii10082 ; B 5 -217 470 460 ;
-C -1 ; WX 444 ; N afii10083 ; B 25 -10 412 460 ;
-C -1 ; WX 456 ; N afii10084 ; B 31 0 425 450 ;
-C -1 ; WX 500 ; N afii10085 ; B 14 -218 475 450 ;
-C -1 ; WX 709 ; N afii10086 ; B 27 -217 679 683 ;
-C -1 ; WX 500 ; N afii10087 ; B 17 0 479 450 ;
-C -1 ; WX 497 ; N afii10088 ; B 15 -125 485 450 ;
-C -1 ; WX 480 ; N afii10089 ; B 13 0 465 450 ;
-C -1 ; WX 698 ; N afii10090 ; B 15 0 683 450 ;
-C -1 ; WX 705 ; N afii10091 ; B 15 -122 686 450 ;
-C -1 ; WX 495 ; N afii10092 ; B 14 0 480 450 ;
-C -1 ; WX 620 ; N afii10093 ; B 15 0 605 450 ;
-C -1 ; WX 426 ; N afii10094 ; B 15 0 404 450 ;
-C -1 ; WX 446 ; N afii10095 ; B 28 -9 416 460 ;
-C -1 ; WX 666 ; N afii10096 ; B 15 -10 637 460 ;
-C -1 ; WX 499 ; N afii10097 ; B 13 0 484 450 ;
-C -1 ; WX 611 ; N uni0400 ; B 12 0 597 883 ;
-C -1 ; WX 768 ; N afii10051 ; B 17 -146 711 662 ;
-C -1 ; WX 556 ; N afii10052 ; B 12 0 546 883 ;
-C -1 ; WX 667 ; N afii10053 ; B 28 -14 633 676 ;
-C -1 ; WX 556 ; N afii10054 ; B 42 -14 491 676 ;
-C -1 ; WX 333 ; N afii10055 ; B 12 0 309 662 ;
-C -1 ; WX 333 ; N afii10056 ; B 12 0 310 811 ;
-C -1 ; WX 389 ; N afii10057 ; B 10 -14 370 662 ;
-C -1 ; WX 969 ; N afii10058 ; B 26 -13 948 662 ;
-C -1 ; WX 980 ; N afii10059 ; B 19 0 948 662 ;
-C -1 ; WX 869 ; N afii10060 ; B 17 0 849 662 ;
-C -1 ; WX 722 ; N afii10061 ; B 34 0 673 883 ;
-C -1 ; WX 722 ; N uni040D ; B 19 0 702 883 ;
-C -1 ; WX 746 ; N afii10062 ; B 20 -12 727 869 ;
-C -1 ; WX 722 ; N afii10145 ; B 19 -183 702 662 ;
-C -1 ; WX 444 ; N uni0450 ; B 25 -10 424 681 ;
-C -1 ; WX 548 ; N afii10099 ; B 9 -217 473 683 ;
-C -1 ; WX 400 ; N afii10100 ; B 15 0 367 681 ;
-C -1 ; WX 444 ; N afii10101 ; B 25 -10 412 460 ;
-C -1 ; WX 389 ; N afii10102 ; B 51 -10 348 459 ;
-C -1 ; WX 278 ; N afii10103 ; B 16 0 253 683 ;
-C -1 ; WX 278 ; N afii10104 ; B -14 0 284 599 ;
-C -1 ; WX 278 ; N afii10105 ; B -70 -218 194 683 ;
-C -1 ; WX 714 ; N afii10106 ; B 14 -9 698 450 ;
-C -1 ; WX 706 ; N afii10107 ; B 18 0 688 450 ;
-C -1 ; WX 548 ; N afii10108 ; B 9 0 535 683 ;
-C -1 ; WX 508 ; N afii10109 ; B 15 0 498 681 ;
-C -1 ; WX 512 ; N uni045D ; B 15 0 497 681 ;
-C -1 ; WX 500 ; N afii10110 ; B 14 -218 475 667 ;
-C -1 ; WX 500 ; N afii10193 ; B 18 -130 485 450 ;
-C -1 ; WX 556 ; N uni048C ; B 16 0 542 662 ;
-C -1 ; WX 504 ; N uni048D ; B 15 0 426 450 ;
-C -1 ; WX 556 ; N uni048E ; B 16 0 547 662 ;
-C -1 ; WX 500 ; N uni048F ; B 5 -217 486 460 ;
-C -1 ; WX 556 ; N afii10050 ; B 12 0 546 767 ;
-C -1 ; WX 418 ; N afii10098 ; B 18 0 385 538 ;
-C -1 ; WX 556 ; N uni0492 ; B 12 0 546 662 ;
-C -1 ; WX 418 ; N uni0493 ; B 18 0 385 450 ;
-C -1 ; WX 573 ; N uni0494 ; B 12 -218 581 662 ;
-C -1 ; WX 468 ; N uni0495 ; B 18 -218 440 450 ;
-C -1 ; WX 1053 ; N uni0496 ; B 36 -129 1031 668 ;
-C -1 ; WX 766 ; N uni0497 ; B 25 -108 740 460 ;
-C -1 ; WX 508 ; N uni0498 ; B 10 -165 479 675 ;
-C -1 ; WX 363 ; N uni0499 ; B 34 -165 353 459 ;
-C -1 ; WX 722 ; N uni049A ; B 34 -129 691 668 ;
-C -1 ; WX 500 ; N uni049B ; B 7 -108 493 460 ;
-C -1 ; WX 722 ; N uni049C ; B 34 0 673 668 ;
-C -1 ; WX 500 ; N uni049D ; B 7 0 490 460 ;
-C -1 ; WX 722 ; N uni049E ; B 34 0 673 668 ;
-C -1 ; WX 500 ; N uni049F ; B 7 0 490 460 ;
-C -1 ; WX 852 ; N uni04A0 ; B 17 0 803 668 ;
-C -1 ; WX 671 ; N uni04A1 ; B 7 0 585 460 ;
-C -1 ; WX 722 ; N uni04A2 ; B 19 -129 710 662 ;
-C -1 ; WX 500 ; N uni04A3 ; B 18 -108 490 450 ;
-C -1 ; WX 984 ; N uni04A4 ; B 19 0 958 662 ;
-C -1 ; WX 660 ; N uni04A5 ; B 18 0 644 450 ;
-C -1 ; WX 1014 ; N uni04A6 ; B 19 -218 994 662 ;
-C -1 ; WX 714 ; N uni04A7 ; B 18 -218 699 450 ;
-C -1 ; WX 732 ; N uni04A8 ; B 28 -14 702 676 ;
-C -1 ; WX 444 ; N uni04A9 ; B 25 -12 435 460 ;
-C -1 ; WX 667 ; N uni04AA ; B 28 -165 633 676 ;
-C -1 ; WX 444 ; N uni04AB ; B 25 -165 412 460 ;
-C -1 ; WX 611 ; N uni04AC ; B 17 -129 593 662 ;
-C -1 ; WX 484 ; N uni04AD ; B 31 -108 455 450 ;
-C -1 ; WX 722 ; N uni04AE ; B 22 0 703 662 ;
-C -1 ; WX 500 ; N uni04AF ; B 19 -196 477 450 ;
-C -1 ; WX 722 ; N uni04B0 ; B 22 0 703 662 ;
-C -1 ; WX 500 ; N uni04B1 ; B 19 -196 477 450 ;
-C -1 ; WX 722 ; N uni04B2 ; B 10 -129 710 662 ;
-C -1 ; WX 500 ; N uni04B3 ; B 17 -108 492 450 ;
-C -1 ; WX 967 ; N uni04B4 ; B 17 -129 955 662 ;
-C -1 ; WX 723 ; N uni04B5 ; B 31 -108 694 450 ;
-C -1 ; WX 722 ; N uni04B6 ; B 19 -129 710 662 ;
-C -1 ; WX 500 ; N uni04B7 ; B 18 -108 475 450 ;
-C -1 ; WX 722 ; N uni04B8 ; B 19 1 702 663 ;
-C -1 ; WX 500 ; N uni04B9 ; B 18 -1 470 450 ;
-C -1 ; WX 722 ; N uni04BA ; B 19 0 702 662 ;
-C -1 ; WX 500 ; N uni04BB ; B 18 0 470 450 ;
-C -1 ; WX 838 ; N uni04BC ; B 26 -14 773 705 ;
-C -1 ; WX 523 ; N uni04BD ; B 13 -10 503 488 ;
-C -1 ; WX 838 ; N uni04BE ; B 26 -165 773 705 ;
-C -1 ; WX 523 ; N uni04BF ; B 13 -165 503 488 ;
-C -1 ; WX 333 ; N uni04C0 ; B 12 0 309 662 ;
-C -1 ; WX 948 ; N uni04C1 ; B 11 0 927 879 ;
-C -1 ; WX 669 ; N uni04C2 ; B 14 0 656 667 ;
-C -1 ; WX 722 ; N uni04C3 ; B 34 -218 655 668 ;
-C -1 ; WX 500 ; N uni04C4 ; B 7 -219 468 460 ;
-C -1 ; WX 722 ; N uni04C7 ; B 19 -177 702 662 ;
-C -1 ; WX 500 ; N uni04C8 ; B 18 -218 485 450 ;
-C -1 ; WX 722 ; N uni04CB ; B 19 -129 702 662 ;
-C -1 ; WX 500 ; N uni04CC ; B 18 -108 470 450 ;
-C -1 ; WX 722 ; N uni04D0 ; B 15 0 706 869 ;
-C -1 ; WX 444 ; N uni04D1 ; B 37 -10 442 657 ;
-C -1 ; WX 722 ; N uni04D2 ; B 15 0 706 811 ;
-C -1 ; WX 444 ; N uni04D3 ; B 37 -10 442 599 ;
-C -1 ; WX 889 ; N uni04D4 ; B 0 0 863 662 ;
-C -1 ; WX 667 ; N uni04D5 ; B 38 -10 632 460 ;
-C -1 ; WX 611 ; N uni04D6 ; B 12 0 597 869 ;
-C -1 ; WX 444 ; N uni04D7 ; B 25 -10 424 657 ;
-C -1 ; WX 716 ; N uni04D8 ; B 56 -10 682 696 ;
-C -1 ; WX 444 ; N afii10846 ; B 25 -10 424 460 ;
-C -1 ; WX 716 ; N uni04DA ; B 56 -10 682 815 ;
-C -1 ; WX 444 ; N uni04DB ; B 24 -10 423 599 ;
-C -1 ; WX 948 ; N uni04DC ; B 11 0 927 821 ;
-C -1 ; WX 669 ; N uni04DD ; B 14 0 656 609 ;
-C -1 ; WX 508 ; N uni04DE ; B 10 -14 479 795 ;
-C -1 ; WX 363 ; N uni04DF ; B 27 -10 353 579 ;
-C -1 ; WX 556 ; N uni04E0 ; B 14 -14 496 676 ;
-C -1 ; WX 389 ; N uni04E1 ; B 28 -10 354 450 ;
-C -1 ; WX 715 ; N uni04E2 ; B 12 0 695 776 ;
-C -1 ; WX 512 ; N uni04E3 ; B 15 0 497 564 ;
-C -1 ; WX 715 ; N uni04E4 ; B 12 0 695 821 ;
-C -1 ; WX 512 ; N uni04E5 ; B 15 0 497 609 ;
-C -1 ; WX 722 ; N uni04E6 ; B 34 -14 688 821 ;
-C -1 ; WX 500 ; N uni04E7 ; B 29 -10 470 609 ;
-C -1 ; WX 722 ; N uni04E8 ; B 34 -14 688 676 ;
-C -1 ; WX 500 ; N uni04E9 ; B 29 -10 470 460 ;
-C -1 ; WX 722 ; N uni04EA ; B 34 -14 688 811 ;
-C -1 ; WX 500 ; N uni04EB ; B 29 -10 470 599 ;
-C -1 ; WX 649 ; N uni04EC ; B 10 -14 615 821 ;
-C -1 ; WX 446 ; N uni04ED ; B 28 -9 416 610 ;
-C -1 ; WX 716 ; N uni04EE ; B 20 -12 686 776 ;
-C -1 ; WX 500 ; N uni04EF ; B 14 -218 475 564 ;
-C -1 ; WX 716 ; N uni04F0 ; B 20 -12 686 821 ;
-C -1 ; WX 500 ; N uni04F1 ; B 14 -218 475 609 ;
-C -1 ; WX 716 ; N uni04F2 ; B 20 -12 686 893 ;
-C -1 ; WX 500 ; N uni04F3 ; B 14 -218 475 681 ;
-C -1 ; WX 701 ; N uni04F4 ; B 19 0 681 821 ;
-C -1 ; WX 480 ; N uni04F5 ; B 13 0 465 609 ;
-C -1 ; WX 855 ; N uni04F8 ; B 12 0 835 821 ;
-C -1 ; WX 620 ; N uni04F9 ; B 15 0 605 609 ;
-C -1 ; WX 400 ; N uniF6C4 ; B 15 0 367 450 ;
-C -1 ; WX 500 ; N uniF6C5 ; B 28 -10 470 689 ;
-C -1 ; WX 518 ; N uniF6C6 ; B 36 -125 500 450 ;
-C -1 ; WX 517 ; N uniF6C7 ; B 15 0 502 450 ;
-C -1 ; WX 456 ; N uniF6C8 ; B 31 0 425 450 ;
-C -1 ; WX 667 ; N Ccircumflex ; B 28 -14 633 879 ;
-C -1 ; WX 444 ; N ccircumflex ; B 25 -10 412 667 ;
-C -1 ; WX 667 ; N Cdotaccent ; B 28 -14 633 811 ;
-C -1 ; WX 444 ; N cdotaccent ; B 25 -10 412 599 ;
-C -1 ; WX 611 ; N Ebreve ; B 12 0 597 869 ;
-C -1 ; WX 444 ; N ebreve ; B 25 -10 424 657 ;
-C -1 ; WX 722 ; N Gcircumflex ; B 32 -14 709 879 ;
-C -1 ; WX 500 ; N gcircumflex ; B 28 -218 470 667 ;
-C -1 ; WX 722 ; N Gdotaccent ; B 32 -14 709 811 ;
-C -1 ; WX 500 ; N gdotaccent ; B 28 -218 470 599 ;
-C -1 ; WX 722 ; N Hcircumflex ; B 12 0 695 879 ;
-C -1 ; WX 500 ; N hcircumflex ; B 8 0 487 890 ;
-C -1 ; WX 722 ; N Hbar ; B 10 0 711 662 ;
-C -1 ; WX 548 ; N hbar ; B 9 0 535 683 ;
-C -1 ; WX 333 ; N Itilde ; B -4 0 326 818 ;
-C -1 ; WX 278 ; N itilde ; B -30 0 300 606 ;
-C -1 ; WX 333 ; N Ibreve ; B 12 0 309 869 ;
-C -1 ; WX 278 ; N ibreve ; B -6 0 275 657 ;
-C -1 ; WX 694 ; N IJ ; B 12 -14 673 662 ;
-C -1 ; WX 396 ; N ij ; B 16 -214 380 687 ;
-C -1 ; WX 389 ; N Jcircumflex ; B 10 -14 370 879 ;
-C -1 ; WX 278 ; N jcircumflex ; B -70 -218 295 723 ;
-C -1 ; WX 500 ; N kgreenlandic ; B 7 0 490 460 ;
-C -1 ; WX 611 ; N Ldot ; B 12 0 598 662 ;
-C -1 ; WX 416 ; N ldot ; B 19 0 365 683 ;
-C -1 ; WX 598 ; N napostrophe ; B 23 0 582 599 ;
-C -1 ; WX 722 ; N Eng ; B 12 -218 707 662 ;
-C -1 ; WX 500 ; N eng ; B 16 -218 424 460 ;
-C -1 ; WX 722 ; N Obreve ; B 34 -14 688 869 ;
-C -1 ; WX 500 ; N obreve ; B 29 -10 470 657 ;
-C -1 ; WX 556 ; N Scircumflex ; B 42 -14 491 879 ;
-C -1 ; WX 389 ; N scircumflex ; B 44 -10 355 667 ;
-C -1 ; WX 611 ; N Tbar ; B 17 0 593 662 ;
-C -1 ; WX 278 ; N tbar ; B 3 -10 279 579 ;
-C -1 ; WX 722 ; N Utilde ; B 14 -14 705 818 ;
-C -1 ; WX 500 ; N utilde ; B 9 -10 479 606 ;
-C -1 ; WX 722 ; N Ubreve ; B 14 -14 705 869 ;
-C -1 ; WX 500 ; N ubreve ; B 9 -10 479 657 ;
-C -1 ; WX 944 ; N Wcircumflex ; B 5 -11 932 879 ;
-C -1 ; WX 722 ; N wcircumflex ; B 21 -14 694 667 ;
-C -1 ; WX 722 ; N Ycircumflex ; B 22 0 703 879 ;
-C -1 ; WX 500 ; N ycircumflex ; B 14 -218 475 667 ;
-C -1 ; WX 333 ; N longs ; B 20 0 383 683 ;
-C -1 ; WX 954 ; N afii61352 ; B 8 -15 923 669 ;
-C -1 ; WX 677 ; N infinity ; B 25 53 653 434 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 984
-KPX quoteright y -45
-KPX quoteright w -47
-KPX quoteright v -47
-KPX quoteright t -43
-KPX quoteright s -47
-KPX quoteright r -44
-KPX quoteright period -78
-KPX quoteright o -54
-KPX quoteright d -56
-KPX quoteright comma -71
-KPX quoteright Aring -130
-KPX quoteright Adieresis -130
-KPX quoteright Aacute -130
-KPX quoteright AE -135
-KPX quoteright A -130
-KPX comma quoteright -53
-KPX comma quotedblright -29
-KPX comma one -52
-KPX hyphen Y -108
-KPX hyphen W -59
-KPX hyphen V -82
-KPX hyphen T -77
-KPX hyphen Aring -26
-KPX hyphen Adieresis -26
-KPX hyphen Aacute -26
-KPX hyphen AE -25
-KPX hyphen A -26
-KPX period quoteright -58
-KPX period quotedblright -33
-KPX period one -61
-KPX zero seven -5
-KPX zero one -55
-KPX zero four 12
-KPX one zero -54
-KPX one two -34
-KPX one three -41
-KPX one six -66
-KPX one seven -78
-KPX one period -55
-KPX one one -78
-KPX one nine -61
-KPX one four -72
-KPX one five -37
-KPX one eight -68
-KPX one comma -48
-KPX two seven -16
-KPX two one -60
-KPX three seven -28
-KPX three one -75
-KPX three four -6
-KPX four seven -42
-KPX four one -75
-KPX four four 14
-KPX five seven -36
-KPX five one -70
-KPX five four -8
-KPX six seven -29
-KPX six one -74
-KPX six four 12
-KPX seven two -31
-KPX seven three -35
-KPX seven six -46
-KPX seven seven -20
-KPX seven period -79
-KPX seven one -56
-KPX seven four -63
-KPX seven five -59
-KPX seven eight -40
-KPX seven comma -72
-KPX seven colon -68
-KPX eight seven -15
-KPX eight one -64
-KPX nine seven -6
-KPX nine one -63
-KPX nine four -7
-KPX A y -83
-KPX A w -73
-KPX A v -81
-KPX A u -28
-KPX A t -20
-KPX A quoteright -116
-KPX A quotedblright -91
-KPX A q -21
-KPX A period -10
-KPX A o -40
-KPX A hyphen -23
-KPX A guilsinglleft -74
-KPX A guillemotleft -64
-KPX A g -20
-KPX A e -27
-KPX A d -28
-KPX A comma -3
-KPX A ccedilla -29
-KPX A c -29
-KPX A b -20
-KPX A a -6
-KPX A Y -81
-KPX A W -113
-KPX A V -131
-KPX A Ugrave -62
-KPX A Udieresis -62
-KPX A Ucircumflex -62
-KPX A Uacute -62
-KPX A U -62
-KPX A T -54
-KPX A Q -60
-KPX A Odieresis -60
-KPX A O -60
-KPX A G -57
-KPX A Ccedilla -57
-KPX A C -51
-KPX B Y -68
-KPX B W -59
-KPX B V -65
-KPX B Oslash -23
-KPX B Ograve -24
-KPX B Odieresis -24
-KPX B Ocircumflex -24
-KPX B Oacute -24
-KPX B OE -18
-KPX B O -24
-KPX B Atilde -51
-KPX B Aring -51
-KPX B Adieresis -51
-KPX B Acircumflex -51
-KPX B Aacute -51
-KPX B AE -44
-KPX B A -51
-KPX C Odieresis -12
-KPX C Oacute -12
-KPX C O -12
-KPX C K -10
-KPX C H -2
-KPX C Aring -23
-KPX C Adieresis -23
-KPX C Aacute -23
-KPX C AE -15
-KPX C A -23
-KPX D Y -74
-KPX D X -64
-KPX D W -57
-KPX D V -71
-KPX D T -10
-KPX D J -41
-KPX D Atilde -67
-KPX D Aring -67
-KPX D Agrave -67
-KPX D Adieresis -67
-KPX D Acircumflex -67
-KPX D Aacute -67
-KPX D A -67
-KPX F u -11
-KPX F r -10
-KPX F period -58
-KPX F oslash -21
-KPX F oe -21
-KPX F odieresis -21
-KPX F oacute -21
-KPX F o -21
-KPX F j -20
-KPX F i -13
-KPX F hyphen 3
-KPX F eacute -19
-KPX F e -19
-KPX F comma -51
-KPX F aring -34
-KPX F ae -36
-KPX F adieresis -10
-KPX F aacute -34
-KPX F a -34
-KPX F Odieresis -10
-KPX F O -10
-KPX F J -13
-KPX F Atilde -71
-KPX F Aring -71
-KPX F Agrave -71
-KPX F Adieresis -71
-KPX F Acircumflex -71
-KPX F Aacute -71
-KPX F A -71
-KPX G Y -26
-KPX G W -18
-KPX G V -23
-KPX G T -21
-KPX G Atilde -26
-KPX G Aring -26
-KPX G Agrave -26
-KPX G Adieresis -26
-KPX G Acircumflex -26
-KPX G Aacute -26
-KPX G AE -19
-KPX G A -26
-KPX J Aring -53
-KPX J Adieresis -53
-KPX J AE -46
-KPX J A -53
-KPX K y -86
-KPX K udieresis -19
-KPX K u -19
-KPX K odieresis -31
-KPX K oacute -31
-KPX K o -31
-KPX K hyphen -63
-KPX K e -19
-KPX K aring 2
-KPX K adieresis 2
-KPX K a 2
-KPX K S 1
-KPX K Odieresis -51
-KPX K Oacute -51
-KPX K OE -44
-KPX K O -51
-KPX K G -49
-KPX K C -43
-KPX L y -56
-KPX L udieresis -10
-KPX L u -10
-KPX L quoteright -125
-KPX L quotedblright -100
-KPX L hyphen 25
-KPX L Y -100
-KPX L W -89
-KPX L V -115
-KPX L Udieresis -26
-KPX L U -26
-KPX L T -73
-KPX L S 5
-KPX L Otilde -3
-KPX L Ograve -3
-KPX L Odieresis -3
-KPX L Ocircumflex -3
-KPX L Oacute -3
-KPX L O -3
-KPX L C 2
-KPX L AE 6
-KPX N udieresis -25
-KPX N u -25
-KPX N period -21
-KPX N oslash -20
-KPX N odieresis -21
-KPX N oacute -21
-KPX N o -21
-KPX N eacute -17
-KPX N e -17
-KPX N comma -14
-KPX N aring -27
-KPX N ae -27
-KPX N adieresis -27
-KPX N aacute -27
-KPX N a -27
-KPX N Odieresis -20
-KPX N Oacute -20
-KPX N O -20
-KPX N G -19
-KPX N Ccedilla -16
-KPX N C -16
-KPX N Aring -28
-KPX N Adieresis -28
-KPX N Aacute -28
-KPX N AE -21
-KPX N A -28
-KPX O Y -72
-KPX O X -55
-KPX O W -54
-KPX O V -69
-KPX O T -9
-KPX O Aring -58
-KPX O Adieresis -58
-KPX O Aacute -58
-KPX O AE -50
-KPX O A -58
-KPX P period -101
-KPX P oslash -25
-KPX P oe -25
-KPX P odieresis -25
-KPX P oacute -25
-KPX P o -25
-KPX P hyphen -37
-KPX P eacute -23
-KPX P e -23
-KPX P comma -94
-KPX P aring -17
-KPX P ae -18
-KPX P adieresis -17
-KPX P aacute -17
-KPX P a -17
-KPX P J -52
-KPX P Aring -90
-KPX P Adieresis -90
-KPX P Aacute -90
-KPX P AE -91
-KPX P A -90
-KPX R y -37
-KPX R udieresis -24
-KPX R uacute -24
-KPX R u -24
-KPX R oe -31
-KPX R odieresis -36
-KPX R oacute -36
-KPX R o -36
-KPX R hyphen -52
-KPX R eacute -23
-KPX R e -23
-KPX R aring -2
-KPX R ae -5
-KPX R adieresis -2
-KPX R aacute -2
-KPX R a -2
-KPX R Y -76
-KPX R W -67
-KPX R V -73
-KPX R Udieresis -55
-KPX R U -56
-KPX R T -34
-KPX R Odieresis -45
-KPX R Oacute -45
-KPX R OE -39
-KPX R O -45
-KPX R G -44
-KPX R Ccedilla -41
-KPX R C -41
-KPX S t -20
-KPX S Y -30
-KPX S W -21
-KPX S V -27
-KPX S T -19
-KPX S Aring -37
-KPX S Adieresis -37
-KPX S Aacute -37
-KPX S AE -30
-KPX S A -37
-KPX T y -102
-KPX T w -106
-KPX T v -105
-KPX T u -93
-KPX T semicolon -87
-KPX T s -73
-KPX T r -50
-KPX T period -82
-KPX T oslash -89
-KPX T o -90
-KPX T j -25
-KPX T i -18
-KPX T hyphen -73
-KPX T guilsinglleft -125
-KPX T guillemotleft -114
-KPX T g -91
-KPX T e -86
-KPX T comma -74
-KPX T colon -87
-KPX T c -87
-KPX T ae -80
-KPX T a -77
-KPX T Y 11
-KPX T W 20
-KPX T V 14
-KPX T S -10
-KPX T Otilde -10
-KPX T Oslash -10
-KPX T Ograve -10
-KPX T Odieresis -10
-KPX T Ocircumflex -10
-KPX T Oacute -10
-KPX T OE -4
-KPX T O -10
-KPX T J -18
-KPX T G -11
-KPX T C -8
-KPX T Atilde -53
-KPX T Aring -53
-KPX T Agrave -53
-KPX T Adieresis -53
-KPX T Acircumflex -53
-KPX T Aacute -53
-KPX T AE -45
-KPX T A -53
-KPX U r -27
-KPX U period -37
-KPX U p -28
-KPX U n -31
-KPX U m -33
-KPX U comma -31
-KPX U Atilde -65
-KPX U Aring -65
-KPX U Adieresis -65
-KPX U Acircumflex -65
-KPX U Aacute -65
-KPX U AE -58
-KPX U A -65
-KPX V y -54
-KPX V u -51
-KPX V semicolon -89
-KPX V r -56
-KPX V period -112
-KPX V oslash -88
-KPX V o -89
-KPX V i -20
-KPX V hyphen -69
-KPX V guilsinglleft -119
-KPX V guillemotleft -109
-KPX V g -101
-KPX V e -85
-KPX V comma -105
-KPX V colon -90
-KPX V ae -89
-KPX V a -88
-KPX V T 10
-KPX V S -47
-KPX V Otilde -67
-KPX V Oslash -65
-KPX V Ograve -67
-KPX V Odieresis -67
-KPX V Ocircumflex -67
-KPX V Oacute -67
-KPX V O -67
-KPX V G -66
-KPX V C -63
-KPX V Atilde -124
-KPX V Aring -124
-KPX V Agrave -124
-KPX V Adieresis -124
-KPX V Acircumflex -124
-KPX V Aacute -124
-KPX V AE -104
-KPX V A -124
-KPX W y -45
-KPX W u -43
-KPX W semicolon -81
-KPX W r -47
-KPX W period -96
-KPX W oslash -75
-KPX W o -76
-KPX W i -13
-KPX W hyphen -56
-KPX W guilsinglleft -107
-KPX W guillemotleft -97
-KPX W g -91
-KPX W e -72
-KPX W comma -89
-KPX W colon -81
-KPX W ae -81
-KPX W a -80
-KPX W T 17
-KPX W S -41
-KPX W Otilde -56
-KPX W Oslash -55
-KPX W Ograve -56
-KPX W Odieresis -56
-KPX W Ocircumflex -56
-KPX W Oacute -56
-KPX W O -56
-KPX W G -56
-KPX W C -53
-KPX W Atilde -113
-KPX W Aring -113
-KPX W Agrave -113
-KPX W Adieresis -113
-KPX W Acircumflex -113
-KPX W Aacute -113
-KPX W AE -98
-KPX W A -113
-KPX X y -96
-KPX X u -29
-KPX X o -41
-KPX X hyphen -54
-KPX X e -28
-KPX X a -7
-KPX X Q -61
-KPX X Odieresis -61
-KPX X O -61
-KPX X C -52
-KPX Y v -86
-KPX Y u -78
-KPX Y semicolon -108
-KPX Y period -103
-KPX Y p -88
-KPX Y oslash -106
-KPX Y o -107
-KPX Y i -17
-KPX Y hyphen -98
-KPX Y guilsinglleft -145
-KPX Y guillemotleft -135
-KPX Y g -113
-KPX Y e -103
-KPX Y comma -96
-KPX Y colon -109
-KPX Y ae -102
-KPX Y a -99
-KPX Y T 13
-KPX Y S -44
-KPX Y Otilde -69
-KPX Y Oslash -69
-KPX Y Ograve -69
-KPX Y Odieresis -69
-KPX Y Ocircumflex -69
-KPX Y Oacute -69
-KPX Y O -69
-KPX Y G -71
-KPX Y C -68
-KPX Y Atilde -74
-KPX Y Aring -74
-KPX Y Agrave -74
-KPX Y Adieresis -74
-KPX Y Acircumflex -74
-KPX Y Aacute -74
-KPX Y AE -67
-KPX Y A -74
-KPX Z y -50
-KPX Z v -48
-KPX quoteleft Y -26
-KPX quoteleft W -17
-KPX quoteleft V -23
-KPX quoteleft T -9
-KPX quoteleft Aring -110
-KPX quoteleft Adieresis -110
-KPX quoteleft Aacute -110
-KPX quoteleft AE -115
-KPX quoteleft A -110
-KPX a y -32
-KPX a w -31
-KPX a v -30
-KPX a quoteright -40
-KPX a j -26
-KPX b y -32
-KPX b w -30
-KPX b v -29
-KPX c k -19
-KPX c h -15
-KPX e y -30
-KPX e x -35
-KPX e w -28
-KPX e v -27
-KPX e t -10
-KPX e quoteright -30
-KPX f t 10
-KPX f s -21
-KPX f quoteright 17
-KPX f oslash -37
-KPX f oe -36
-KPX f odieresis -1
-KPX f oacute -38
-KPX f o -38
-KPX f l 44
-KPX f j 8
-KPX f i 15
-KPX f f 6
-KPX f eacute -34
-KPX f e -34
-KPX f aring -6
-KPX f ae -25
-KPX f adieresis 12
-KPX f aacute -25
-KPX f a -25
-KPX g r 11
-KPX g odieresis -26
-KPX g oacute -26
-KPX g l -7
-KPX g eacute -25
-KPX g e -25
-KPX g aring -17
-KPX g ae -18
-KPX g adieresis -17
-KPX g a -17
-KPX h y -30
-KPX h quoteright -38
-KPX i j -36
-KPX i T -28
-KPX k udieresis 14
-KPX k u 14
-KPX k s 5
-KPX k period -2
-KPX k odieresis -32
-KPX k oacute -32
-KPX k o -32
-KPX k hyphen -65
-KPX k g -12
-KPX k eacute -19
-KPX k e -19
-KPX k comma 4
-KPX k aring 1
-KPX k ae -1
-KPX k adieresis 1
-KPX k aacute 1
-KPX k a 1
-KPX l y -25
-KPX l v -28
-KPX m y -31
-KPX m w -31
-KPX m v -30
-KPX m p -9
-KPX n y -31
-KPX n w -31
-KPX n v -30
-KPX n quoteright -39
-KPX n p -13
-KPX n T -55
-KPX o y -41
-KPX o x -36
-KPX o w -36
-KPX o v -36
-KPX o t -9
-KPX o quoteright -34
-KPX o T -91
-KPX p y -28
-KPX p t -6
-KPX q u -12
-KPX q c -7
-KPX r z 2
-KPX r y 22
-KPX r x 17
-KPX r w 19
-KPX r v 20
-KPX r u 19
-KPX r t 23
-KPX r semicolon -7
-KPX r r 26
-KPX r quoteright -19
-KPX r q -10
-KPX r period -48
-KPX r p 25
-KPX r oslash -7
-KPX r ograve -8
-KPX r oe -7
-KPX r odieresis -8
-KPX r ocircumflex -8
-KPX r oacute -8
-KPX r o -8
-KPX r n 22
-KPX r m 20
-KPX r l -18
-KPX r k -10
-KPX r j 14
-KPX r i 20
-KPX r hyphen -46
-KPX r h -6
-KPX r g -15
-KPX r f 19
-KPX r egrave -6
-KPX r ecircumflex -6
-KPX r eacute -6
-KPX r e -6
-KPX r d -10
-KPX r comma -41
-KPX r colon -7
-KPX r ccedilla -8
-KPX r c -8
-KPX r aring -1
-KPX r agrave -1
-KPX r ae -3
-KPX r adieresis -1
-KPX r acircumflex -1
-KPX r aacute -1
-KPX r a -1
-KPX s t -15
-KPX s quoteright -38
-KPX t semicolon -8
-KPX t quoteright -29
-KPX t odieresis -8
-KPX t oacute -8
-KPX t o -8
-KPX t h 10
-KPX t colon -8
-KPX t aring 10
-KPX t ae 9
-KPX t adieresis 10
-KPX t aacute 10
-KPX t a 10
-KPX t S 2
-KPX u quoteright -36
-KPX v semicolon -20
-KPX v s -21
-KPX v period -76
-KPX v oslash -38
-KPX v ograve -38
-KPX v odieresis -38
-KPX v oacute -38
-KPX v o -38
-KPX v l -31
-KPX v hyphen -28
-KPX v g -41
-KPX v egrave -36
-KPX v ecircumflex -36
-KPX v eacute -36
-KPX v e -36
-KPX v comma -69
-KPX v colon -20
-KPX v c -37
-KPX v atilde -24
-KPX v aring -24
-KPX v agrave -24
-KPX v ae -24
-KPX v adieresis -24
-KPX v acircumflex -24
-KPX v aacute -24
-KPX v a -24
-KPX w semicolon -23
-KPX w s -23
-KPX w period -71
-KPX w oslash -34
-KPX w ograve -35
-KPX w odieresis -35
-KPX w oacute -35
-KPX w o -35
-KPX w l -33
-KPX w hyphen -24
-KPX w g -43
-KPX w egrave -31
-KPX w ecircumflex -31
-KPX w eacute -31
-KPX w e -31
-KPX w comma -64
-KPX w colon -23
-KPX w c -33
-KPX w atilde -27
-KPX w aring -27
-KPX w agrave -27
-KPX w ae -27
-KPX w adieresis -27
-KPX w acircumflex -27
-KPX w aacute -27
-KPX w a -27
-KPX x q -26
-KPX x o -45
-KPX x eacute -32
-KPX x e -32
-KPX x c -34
-KPX x a -11
-KPX y semicolon -23
-KPX y s -26
-KPX y period -73
-KPX y oslash -38
-KPX y ograve -39
-KPX y odieresis -39
-KPX y oacute -39
-KPX y o -39
-KPX y l -32
-KPX y hyphen -27
-KPX y g -48
-KPX y egrave -35
-KPX y ecircumflex -35
-KPX y eacute -35
-KPX y e -35
-KPX y comma -66
-KPX y colon -23
-KPX y c -37
-KPX y atilde -32
-KPX y aring -32
-KPX y agrave -32
-KPX y ae -31
-KPX y adieresis -32
-KPX y acircumflex -32
-KPX y aacute -32
-KPX y a -32
-KPX quotedblleft Y -1
-KPX quotedblleft W 7
-KPX quotedblleft V 1
-KPX quotedblleft T 14
-KPX quotedblleft Aring -86
-KPX quotedblleft Adieresis -86
-KPX quotedblleft Aacute -86
-KPX quotedblleft AE -91
-KPX quotedblleft A -86
-KPX guilsinglright Y -149
-KPX guilsinglright W -105
-KPX guilsinglright V -128
-KPX guilsinglright T -124
-KPX guilsinglright Aring -72
-KPX guilsinglright Adieresis -72
-KPX guilsinglright Aacute -72
-KPX guilsinglright AE -71
-KPX guilsinglright A -72
-KPX quotedblbase Y -87
-KPX quotedblbase W -76
-KPX quotedblbase V -104
-KPX quotedblbase T -60
-KPX quotedblbase AE 19
-KPX quotedblbase A 12
-KPX quotedblright Y -2
-KPX quotedblright W 6
-KPX quotedblright T 11
-KPX quotedblright Aring -94
-KPX quotedblright Adieresis -94
-KPX quotedblright Aacute -94
-KPX quotedblright AE -99
-KPX quotedblright A -94
-KPX guillemotright Y -138
-KPX guillemotright W -95
-KPX guillemotright V -117
-KPX guillemotright T -114
-KPX guillemotright Aring -62
-KPX guillemotright Adieresis -62
-KPX guillemotright Aacute -62
-KPX guillemotright AE -61
-KPX guillemotright A -62
-KPX Oslash A -58
-KPX ae y -30
-KPX ae w -28
-KPX ae v -27
-KPX Adieresis y -83
-KPX Adieresis w -73
-KPX Adieresis v -81
-KPX Adieresis u -28
-KPX Adieresis t -20
-KPX Adieresis quoteright -116
-KPX Adieresis quotedblright -91
-KPX Adieresis q -21
-KPX Adieresis period -10
-KPX Adieresis o -40
-KPX Adieresis hyphen -23
-KPX Adieresis guilsinglleft -74
-KPX Adieresis guillemotleft -64
-KPX Adieresis g -20
-KPX Adieresis d -28
-KPX Adieresis comma -3
-KPX Adieresis c -29
-KPX Adieresis b -20
-KPX Adieresis a -6
-KPX Adieresis Y -81
-KPX Adieresis W -113
-KPX Adieresis V -131
-KPX Adieresis U -62
-KPX Adieresis T -54
-KPX Adieresis Q -60
-KPX Adieresis O -60
-KPX Adieresis G -57
-KPX Adieresis C -51
-KPX Aacute y -83
-KPX Aacute w -73
-KPX Aacute v -81
-KPX Aacute u -28
-KPX Aacute t -20
-KPX Aacute quoteright -116
-KPX Aacute q -21
-KPX Aacute period -10
-KPX Aacute o -40
-KPX Aacute hyphen -23
-KPX Aacute guilsinglleft -74
-KPX Aacute guillemotleft -64
-KPX Aacute g -20
-KPX Aacute e -27
-KPX Aacute d -28
-KPX Aacute comma -3
-KPX Aacute c -29
-KPX Aacute b -20
-KPX Aacute a -6
-KPX Aacute Y -81
-KPX Aacute W -113
-KPX Aacute V -131
-KPX Aacute U -62
-KPX Aacute T -54
-KPX Aacute Q -60
-KPX Aacute O -60
-KPX Aacute G -57
-KPX Aacute C -51
-KPX Agrave period -10
-KPX Agrave comma -3
-KPX Agrave Y -81
-KPX Agrave W -113
-KPX Agrave V -131
-KPX Agrave U -62
-KPX Agrave T -54
-KPX Agrave Q -60
-KPX Agrave O -60
-KPX Agrave G -57
-KPX Agrave C -51
-KPX Acircumflex period -10
-KPX Acircumflex comma -3
-KPX Acircumflex Y -81
-KPX Acircumflex W -113
-KPX Acircumflex V -131
-KPX Acircumflex U -62
-KPX Acircumflex T -54
-KPX Acircumflex Q -60
-KPX Acircumflex O -60
-KPX Acircumflex G -57
-KPX Acircumflex C -51
-KPX Atilde period -10
-KPX Atilde comma -3
-KPX Atilde Y -81
-KPX Atilde W -113
-KPX Atilde V -131
-KPX Atilde U -62
-KPX Atilde T -54
-KPX Atilde Q -60
-KPX Atilde O -60
-KPX Atilde G -57
-KPX Atilde C -51
-KPX Aring y -83
-KPX Aring w -73
-KPX Aring v -81
-KPX Aring u -28
-KPX Aring t -20
-KPX Aring quoteright -116
-KPX Aring quotedblright -91
-KPX Aring q -21
-KPX Aring period -10
-KPX Aring o -40
-KPX Aring hyphen -23
-KPX Aring guilsinglleft -74
-KPX Aring guillemotleft -64
-KPX Aring g -20
-KPX Aring e -27
-KPX Aring d -28
-KPX Aring comma -3
-KPX Aring c -29
-KPX Aring b -20
-KPX Aring a -6
-KPX Aring Y -81
-KPX Aring W -113
-KPX Aring V -131
-KPX Aring U -62
-KPX Aring T -54
-KPX Aring Q -60
-KPX Aring O -60
-KPX Aring G -57
-KPX Aring C -51
-KPX Ccedilla A -27
-KPX Odieresis Y -72
-KPX Odieresis X -55
-KPX Odieresis W -54
-KPX Odieresis V -69
-KPX Odieresis T -9
-KPX Odieresis A -58
-KPX Oacute Y -72
-KPX Oacute W -54
-KPX Oacute V -69
-KPX Oacute T -9
-KPX Oacute A -58
-KPX Ograve Y -72
-KPX Ograve V -69
-KPX Ograve T -9
-KPX Ocircumflex Y -72
-KPX Ocircumflex V -69
-KPX Ocircumflex T -9
-KPX Otilde Y -72
-KPX Otilde V -69
-KPX Otilde T -9
-KPX Udieresis r -27
-KPX Udieresis period -37
-KPX Udieresis p -28
-KPX Udieresis n -31
-KPX Udieresis m -33
-KPX Udieresis comma -31
-KPX Udieresis b 21
-KPX Udieresis A -65
-KPX Uacute r -27
-KPX Uacute period -37
-KPX Uacute p -28
-KPX Uacute n -31
-KPX Uacute m -33
-KPX Uacute comma -31
-KPX Uacute A -65
-KPX Ugrave A -65
-KPX Ucircumflex A -65
-KPX adieresis y -32
-KPX adieresis w -31
-KPX adieresis v -30
-KPX aacute y -32
-KPX aacute w -31
-KPX aacute v -30
-KPX agrave y -32
-KPX agrave w -31
-KPX agrave v -30
-KPX aring y -32
-KPX aring w -31
-KPX aring v -30
-KPX eacute y -30
-KPX eacute w -28
-KPX eacute v -27
-KPX ecircumflex y -30
-KPX ecircumflex w -28
-KPX ecircumflex v -27
-KPX odieresis y -41
-KPX odieresis x -36
-KPX odieresis w -36
-KPX odieresis v -36
-KPX odieresis t -9
-KPX oacute y -41
-KPX oacute w -36
-KPX oacute v -36
-KPX ograve y -41
-KPX ograve w -36
-KPX ograve v -36
-KPX ocircumflex t -9
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-roman-no-9-l/n021003l.pfb b/src/fonts/nimbus-roman-no-9-l/n021003l.pfb
deleted file mode 100644
index 1f6f6d8..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021003l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-roman-no-9-l/n021003l.pfm b/src/fonts/nimbus-roman-no-9-l/n021003l.pfm
deleted file mode 100644
index 8b873ec..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021003l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-roman-no-9-l/n021004l.afm b/src/fonts/nimbus-roman-no-9-l/n021004l.afm
deleted file mode 100644
index dfc2670..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021004l.afm
+++ /dev/null
@@ -1,1571 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 13:15:44 2007
-FontName NimbusRomNo9L-Medi
-FullName Nimbus Roman No9 L Medium
-FamilyName Nimbus Roman No9 L
-Weight Bold
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle 0
-IsFixedPitch false
-UnderlinePosition -100
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -168 -341 1093 960
-CapHeight 676
-XHeight 461
-Ascender 676
-Descender -205
-StartCharMetrics 562
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 81 -13 251 691 ;
-C 34 ; WX 555 ; N quotedbl ; B 83 404 472 691 ;
-C 35 ; WX 500 ; N numbersign ; B 4 0 496 700 ;
-C 36 ; WX 500 ; N dollar ; B 29 -99 472 750 ;
-C 37 ; WX 1000 ; N percent ; B 124 -14 877 692 ;
-C 38 ; WX 833 ; N ampersand ; B 62 -16 787 691 ;
-C 39 ; WX 333 ; N quoteright ; B 79 356 263 691 ;
-C 40 ; WX 333 ; N parenleft ; B 46 -168 306 694 ;
-C 41 ; WX 333 ; N parenright ; B 27 -168 287 694 ;
-C 42 ; WX 500 ; N asterisk ; B 56 255 447 691 ;
-C 43 ; WX 570 ; N plus ; B 33 0 537 506 ;
-C 44 ; WX 250 ; N comma ; B 39 -180 223 155 ;
-C 45 ; WX 333 ; N hyphen ; B 44 171 287 287 ;
-C 46 ; WX 250 ; N period ; B 41 -13 210 156 ;
-C 47 ; WX 278 ; N slash ; B -24 -19 302 691 ;
-C 48 ; WX 500 ; N zero ; B 24 -13 476 688 ;
-C 49 ; WX 500 ; N one ; B 65 0 442 688 ;
-C 50 ; WX 500 ; N two ; B 17 0 478 688 ;
-C 51 ; WX 500 ; N three ; B 16 -14 468 688 ;
-C 52 ; WX 500 ; N four ; B 19 0 475 688 ;
-C 53 ; WX 500 ; N five ; B 22 -8 470 676 ;
-C 54 ; WX 500 ; N six ; B 28 -13 475 688 ;
-C 55 ; WX 500 ; N seven ; B 17 0 477 676 ;
-C 56 ; WX 500 ; N eight ; B 28 -13 472 688 ;
-C 57 ; WX 500 ; N nine ; B 26 -13 473 688 ;
-C 58 ; WX 333 ; N colon ; B 82 -13 251 472 ;
-C 59 ; WX 333 ; N semicolon ; B 82 -180 266 472 ;
-C 60 ; WX 570 ; N less ; B 31 -12 539 518 ;
-C 61 ; WX 570 ; N equal ; B 33 107 537 399 ;
-C 62 ; WX 570 ; N greater ; B 31 -12 539 518 ;
-C 63 ; WX 500 ; N question ; B 57 -13 445 689 ;
-C 64 ; WX 930 ; N at ; B 108 -19 822 691 ;
-C 65 ; WX 722 ; N A ; B 9 0 689 690 ;
-C 66 ; WX 667 ; N B ; B 16 0 619 676 ;
-C 67 ; WX 722 ; N C ; B 49 -19 687 691 ;
-C 68 ; WX 722 ; N D ; B 14 0 690 676 ;
-C 69 ; WX 667 ; N E ; B 16 0 641 676 ;
-C 70 ; WX 611 ; N F ; B 16 0 583 676 ;
-C 71 ; WX 778 ; N G ; B 37 -19 755 691 ;
-C 72 ; WX 778 ; N H ; B 21 0 759 676 ;
-C 73 ; WX 389 ; N I ; B 20 0 370 676 ; L J IJ ;
-C 74 ; WX 500 ; N J ; B 3 -96 479 676 ;
-C 75 ; WX 778 ; N K ; B 30 0 769 676 ;
-C 76 ; WX 667 ; N L ; B 19 0 638 676 ; L periodcentered Ldot ;
-C 77 ; WX 944 ; N M ; B 14 0 921 676 ;
-C 78 ; WX 722 ; N N ; B 16 -18 701 676 ; L o afii61352 ;
-C 79 ; WX 778 ; N O ; B 35 -19 743 691 ;
-C 80 ; WX 611 ; N P ; B 16 0 600 676 ;
-C 81 ; WX 778 ; N Q ; B 35 -176 743 691 ;
-C 82 ; WX 722 ; N R ; B 26 0 715 676 ;
-C 83 ; WX 556 ; N S ; B 35 -19 513 692 ;
-C 84 ; WX 667 ; N T ; B 31 0 636 676 ; L M trademark ;
-C 85 ; WX 722 ; N U ; B 16 -19 701 676 ;
-C 86 ; WX 722 ; N V ; B 16 -18 701 676 ;
-C 87 ; WX 1000 ; N W ; B 19 -15 981 676 ;
-C 88 ; WX 722 ; N X ; B 16 0 699 676 ;
-C 89 ; WX 722 ; N Y ; B 15 0 699 676 ;
-C 90 ; WX 667 ; N Z ; B 28 0 634 676 ;
-C 91 ; WX 333 ; N bracketleft ; B 67 -149 301 678 ;
-C 92 ; WX 278 ; N backslash ; B -25 -19 303 691 ;
-C 93 ; WX 333 ; N bracketright ; B 32 -149 266 678 ;
-C 94 ; WX 581 ; N asciicircum ; B 73 311 509 676 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 70 356 254 691 ;
-C 97 ; WX 500 ; N a ; B 25 -14 488 473 ;
-C 98 ; WX 556 ; N b ; B 17 -14 521 676 ;
-C 99 ; WX 444 ; N c ; B 25 -14 430 473 ;
-C 100 ; WX 556 ; N d ; B 25 -14 534 676 ;
-C 101 ; WX 444 ; N e ; B 25 -14 426 473 ;
-C 102 ; WX 333 ; N f ; B 14 0 389 691 ; L l fl ; L i fi ;
-C 103 ; WX 500 ; N g ; B 28 -206 483 473 ;
-C 104 ; WX 556 ; N h ; B 16 0 534 676 ;
-C 105 ; WX 278 ; N i ; B 16 0 255 691 ; L j ij ;
-C 106 ; WX 333 ; N j ; B -57 -203 263 691 ;
-C 107 ; WX 556 ; N k ; B 22 0 543 676 ;
-C 108 ; WX 278 ; N l ; B 16 0 255 676 ; L periodcentered ldot ;
-C 109 ; WX 833 ; N m ; B 16 0 814 473 ;
-C 110 ; WX 556 ; N n ; B 21 0 539 473 ;
-C 111 ; WX 500 ; N o ; B 25 -14 476 473 ;
-C 112 ; WX 556 ; N p ; B 19 -205 524 473 ;
-C 113 ; WX 556 ; N q ; B 34 -205 536 473 ;
-C 114 ; WX 444 ; N r ; B 29 0 434 473 ;
-C 115 ; WX 389 ; N s ; B 25 -14 361 473 ;
-C 116 ; WX 333 ; N t ; B 20 -12 332 630 ;
-C 117 ; WX 556 ; N u ; B 16 -14 537 461 ;
-C 118 ; WX 500 ; N v ; B 21 -14 485 461 ;
-C 119 ; WX 722 ; N w ; B 23 -14 707 461 ;
-C 120 ; WX 500 ; N x ; B 12 0 484 461 ;
-C 121 ; WX 500 ; N y ; B 16 -205 480 461 ;
-C 122 ; WX 444 ; N z ; B 21 0 420 461 ;
-C 123 ; WX 394 ; N braceleft ; B 22 -175 340 698 ;
-C 124 ; WX 220 ; N bar ; B 66 -19 154 691 ;
-C 125 ; WX 394 ; N braceright ; B 54 -175 372 698 ;
-C 126 ; WX 520 ; N asciitilde ; B 29 175 491 331 ;
-C 161 ; WX 333 ; N exclamdown ; B 82 -203 252 501 ;
-C 162 ; WX 500 ; N cent ; B 53 -140 458 588 ;
-C 163 ; WX 500 ; N sterling ; B 21 -14 477 684 ;
-C 164 ; WX 167 ; N fraction ; B -168 -12 329 688 ;
-C 165 ; WX 500 ; N yen ; B -64 0 547 676 ;
-C 166 ; WX 500 ; N florin ; B 0 -155 498 706 ;
-C 167 ; WX 500 ; N section ; B 57 -132 443 691 ;
-C 168 ; WX 500 ; N currency ; B -26 61 526 613 ;
-C 169 ; WX 278 ; N quotesingle ; B 75 404 204 691 ;
-C 170 ; WX 500 ; N quotedblleft ; B 32 356 486 691 ;
-C 171 ; WX 500 ; N guillemotleft ; B 23 36 473 415 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 51 36 305 415 ;
-C 173 ; WX 333 ; N guilsinglright ; B 28 36 282 415 ;
-C 174 ; WX 556 ; N fi ; B 14 0 536 691 ;
-C 175 ; WX 556 ; N fl ; B 14 0 536 691 ;
-C 177 ; WX 500 ; N endash ; B 0 181 500 271 ;
-C 178 ; WX 500 ; N dagger ; B 47 -134 453 691 ;
-C 179 ; WX 500 ; N daggerdbl ; B 45 -132 456 691 ;
-C 180 ; WX 250 ; N periodcentered ; B 41 248 210 417 ;
-C 182 ; WX 540 ; N paragraph ; B 0 -186 519 676 ;
-C 183 ; WX 350 ; N bullet ; B 35 198 315 478 ;
-C 184 ; WX 333 ; N quotesinglbase ; B 79 -180 263 155 ;
-C 185 ; WX 500 ; N quotedblbase ; B 14 -180 468 155 ;
-C 186 ; WX 500 ; N quotedblright ; B 14 356 468 691 ;
-C 187 ; WX 500 ; N guillemotright ; B 27 36 477 415 ;
-C 188 ; WX 1000 ; N ellipsis ; B 82 -13 917 156 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -29 995 706 ;
-C 191 ; WX 500 ; N questiondown ; B 55 -201 443 501 ;
-C 193 ; WX 333 ; N grave ; B 8 528 246 713 ;
-C 194 ; WX 333 ; N acute ; B 86 528 324 713 ;
-C 195 ; WX 333 ; N circumflex ; B -2 528 335 704 ;
-C 196 ; WX 333 ; N tilde ; B -16 547 349 674 ;
-C 197 ; WX 333 ; N macron ; B 1 565 331 637 ;
-C 198 ; WX 333 ; N breve ; B 15 528 318 691 ;
-C 199 ; WX 333 ; N dotaccent ; B 103 537 232 666 ;
-C 200 ; WX 333 ; N dieresis ; B -2 537 337 666 ;
-C 202 ; WX 333 ; N ring ; B 60 537 273 750 ;
-C 203 ; WX 333 ; N cedilla ; B 68 -218 294 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B -13 528 425 713 ;
-C 206 ; WX 333 ; N ogonek ; B 90 -173 319 44 ;
-C 207 ; WX 333 ; N caron ; B -2 528 335 704 ;
-C 208 ; WX 1000 ; N emdash ; B 0 181 1000 271 ;
-C 225 ; WX 1000 ; N AE ; B 4 0 951 676 ;
-C 227 ; WX 300 ; N ordfeminine ; B -1 397 301 688 ;
-C 232 ; WX 667 ; N Lslash ; B 19 0 638 676 ;
-C 233 ; WX 778 ; N Oslash ; B 35 -74 743 737 ;
-C 234 ; WX 1000 ; N OE ; B 22 -5 981 684 ;
-C 235 ; WX 330 ; N ordmasculine ; B 18 397 312 688 ;
-C 241 ; WX 722 ; N ae ; B 33 -14 693 473 ;
-C 245 ; WX 278 ; N dotlessi ; B 16 0 255 461 ;
-C 248 ; WX 278 ; N lslash ; B -22 0 303 676 ;
-C 249 ; WX 500 ; N oslash ; B 25 -92 476 549 ;
-C 250 ; WX 722 ; N oe ; B 22 -14 696 473 ;
-C 251 ; WX 556 ; N germandbls ; B 19 -12 517 691 ;
-C -1 ; WX 722 ; N Adieresis ; B 9 0 689 876 ;
-C -1 ; WX 722 ; N Aacute ; B 9 0 689 923 ;
-C -1 ; WX 722 ; N Agrave ; B 9 0 689 923 ;
-C -1 ; WX 722 ; N Acircumflex ; B 9 0 689 914 ;
-C -1 ; WX 722 ; N Abreve ; B 9 0 689 901 ;
-C -1 ; WX 722 ; N Atilde ; B 9 0 689 884 ;
-C -1 ; WX 722 ; N Aring ; B 9 0 689 948 ;
-C -1 ; WX 722 ; N Aogonek ; B 9 -173 822 690 ;
-C -1 ; WX 722 ; N Ccedilla ; B 49 -218 687 691 ;
-C -1 ; WX 722 ; N Cacute ; B 49 -19 687 923 ;
-C -1 ; WX 722 ; N Ccaron ; B 49 -19 687 914 ;
-C -1 ; WX 722 ; N Dcaron ; B 14 0 690 914 ;
-C -1 ; WX 667 ; N Edieresis ; B 16 0 641 876 ;
-C -1 ; WX 667 ; N Eacute ; B 16 0 641 923 ;
-C -1 ; WX 667 ; N Egrave ; B 16 0 641 923 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 16 0 641 914 ;
-C -1 ; WX 667 ; N Ecaron ; B 16 0 641 914 ;
-C -1 ; WX 667 ; N Edotaccent ; B 16 0 641 876 ;
-C -1 ; WX 667 ; N Eogonek ; B 16 -173 737 676 ;
-C -1 ; WX 778 ; N Gbreve ; B 37 -19 755 901 ;
-C -1 ; WX 389 ; N Idieresis ; B 20 0 370 876 ;
-C -1 ; WX 389 ; N Iacute ; B 20 0 370 923 ;
-C -1 ; WX 389 ; N Igrave ; B 20 0 370 923 ;
-C -1 ; WX 389 ; N Icircumflex ; B 20 0 370 914 ;
-C -1 ; WX 389 ; N Idotaccent ; B 20 0 370 876 ;
-C -1 ; WX 667 ; N Lacute ; B 19 0 638 923 ;
-C -1 ; WX 667 ; N Lcaron ; B 19 0 638 691 ;
-C -1 ; WX 722 ; N Nacute ; B 16 -18 701 923 ;
-C -1 ; WX 722 ; N Ncaron ; B 16 -18 701 914 ;
-C -1 ; WX 722 ; N Ntilde ; B 16 -18 701 884 ;
-C -1 ; WX 778 ; N Odieresis ; B 35 -19 743 876 ;
-C -1 ; WX 778 ; N Oacute ; B 35 -19 743 923 ;
-C -1 ; WX 778 ; N Ograve ; B 35 -19 743 923 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 35 -19 743 914 ;
-C -1 ; WX 778 ; N Otilde ; B 35 -19 743 884 ;
-C -1 ; WX 778 ; N Ohungarumlaut ; B 35 -19 743 923 ;
-C -1 ; WX 722 ; N Racute ; B 26 0 715 923 ;
-C -1 ; WX 722 ; N Rcaron ; B 26 0 715 914 ;
-C -1 ; WX 556 ; N Sacute ; B 35 -19 513 923 ;
-C -1 ; WX 556 ; N Scaron ; B 35 -19 513 914 ;
-C -1 ; WX 556 ; N Scedilla ; B 35 -218 513 692 ;
-C -1 ; WX 667 ; N Tcaron ; B 31 0 636 914 ;
-C -1 ; WX 722 ; N Udieresis ; B 16 -19 701 876 ;
-C -1 ; WX 722 ; N Uacute ; B 16 -19 701 923 ;
-C -1 ; WX 722 ; N Ugrave ; B 16 -19 701 923 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 16 -19 701 914 ;
-C -1 ; WX 722 ; N Uring ; B 16 -19 701 960 ;
-C -1 ; WX 722 ; N Uhungarumlaut ; B 16 -19 701 923 ;
-C -1 ; WX 722 ; N Yacute ; B 15 0 699 923 ;
-C -1 ; WX 667 ; N Zacute ; B 28 0 634 923 ;
-C -1 ; WX 667 ; N Zcaron ; B 28 0 634 914 ;
-C -1 ; WX 667 ; N Zdotaccent ; B 28 0 634 876 ;
-C -1 ; WX 722 ; N Amacron ; B 9 0 689 847 ;
-C -1 ; WX 667 ; N Tcommaaccent ; B 31 -341 636 676 ;
-C -1 ; WX 722 ; N Ydieresis ; B 15 0 699 876 ;
-C -1 ; WX 667 ; N Emacron ; B 16 0 641 847 ;
-C -1 ; WX 389 ; N Imacron ; B 20 0 370 847 ;
-C -1 ; WX 389 ; N Iogonek ; B 20 -173 505 676 ;
-C -1 ; WX 778 ; N Kcommaaccent ; B 30 -341 769 676 ;
-C -1 ; WX 667 ; N Lcommaaccent ; B 19 -341 638 676 ;
-C -1 ; WX 722 ; N Ncommaaccent ; B 16 -341 701 676 ;
-C -1 ; WX 778 ; N Omacron ; B 35 -19 743 847 ;
-C -1 ; WX 722 ; N Rcommaaccent ; B 26 -341 715 676 ;
-C -1 ; WX 778 ; N Gcommaaccent ; B 37 -341 755 691 ;
-C -1 ; WX 722 ; N Umacron ; B 16 -19 701 847 ;
-C -1 ; WX 722 ; N Uogonek ; B 16 -173 701 676 ;
-C -1 ; WX 500 ; N adieresis ; B 25 -14 488 666 ;
-C -1 ; WX 500 ; N aacute ; B 25 -14 488 713 ;
-C -1 ; WX 500 ; N agrave ; B 25 -14 488 713 ;
-C -1 ; WX 500 ; N acircumflex ; B 25 -14 488 704 ;
-C -1 ; WX 500 ; N abreve ; B 25 -14 488 691 ;
-C -1 ; WX 500 ; N atilde ; B 25 -14 488 674 ;
-C -1 ; WX 500 ; N aring ; B 25 -14 488 750 ;
-C -1 ; WX 500 ; N aogonek ; B 25 -173 500 473 ;
-C -1 ; WX 444 ; N cacute ; B 25 -14 430 713 ;
-C -1 ; WX 444 ; N ccaron ; B 25 -14 430 704 ;
-C -1 ; WX 444 ; N ccedilla ; B 25 -218 430 473 ;
-C -1 ; WX 665 ; N dcaron ; B 25 -14 665 691 ;
-C -1 ; WX 444 ; N edieresis ; B 25 -14 426 666 ;
-C -1 ; WX 444 ; N eacute ; B 25 -14 426 713 ;
-C -1 ; WX 444 ; N egrave ; B 25 -14 426 713 ;
-C -1 ; WX 444 ; N ecircumflex ; B 25 -14 426 704 ;
-C -1 ; WX 444 ; N ecaron ; B 25 -14 426 704 ;
-C -1 ; WX 444 ; N edotaccent ; B 25 -14 426 666 ;
-C -1 ; WX 444 ; N eogonek ; B 25 -173 444 473 ;
-C -1 ; WX 500 ; N gbreve ; B 28 -206 483 691 ;
-C -1 ; WX 278 ; N idieresis ; B -36 0 303 666 ;
-C -1 ; WX 278 ; N iacute ; B 16 0 290 713 ;
-C -1 ; WX 278 ; N igrave ; B -26 0 255 713 ;
-C -1 ; WX 278 ; N icircumflex ; B -36 0 301 704 ;
-C -1 ; WX 278 ; N lacute ; B 16 0 297 923 ;
-C -1 ; WX 396 ; N lcaron ; B 16 0 396 691 ;
-C -1 ; WX 556 ; N nacute ; B 21 0 539 713 ;
-C -1 ; WX 556 ; N ncaron ; B 21 0 539 704 ;
-C -1 ; WX 556 ; N ntilde ; B 21 0 539 674 ;
-C -1 ; WX 500 ; N odieresis ; B 25 -14 476 666 ;
-C -1 ; WX 500 ; N oacute ; B 25 -14 476 713 ;
-C -1 ; WX 500 ; N ograve ; B 25 -14 476 713 ;
-C -1 ; WX 500 ; N ocircumflex ; B 25 -14 476 704 ;
-C -1 ; WX 500 ; N otilde ; B 25 -14 476 674 ;
-C -1 ; WX 500 ; N ohungarumlaut ; B 25 -14 509 713 ;
-C -1 ; WX 444 ; N racute ; B 29 0 434 713 ;
-C -1 ; WX 389 ; N sacute ; B 25 -14 361 713 ;
-C -1 ; WX 389 ; N scaron ; B 25 -14 363 704 ;
-C -1 ; WX 389 ; N scommaaccent ; B 25 -341 361 473 ;
-C -1 ; WX 400 ; N tcaron ; B 20 -12 400 691 ;
-C -1 ; WX 556 ; N udieresis ; B 16 -14 537 666 ;
-C -1 ; WX 556 ; N uacute ; B 16 -14 537 713 ;
-C -1 ; WX 556 ; N ugrave ; B 16 -14 537 713 ;
-C -1 ; WX 556 ; N ucircumflex ; B 16 -14 537 704 ;
-C -1 ; WX 556 ; N uring ; B 16 -14 537 750 ;
-C -1 ; WX 556 ; N uhungarumlaut ; B 16 -14 537 713 ;
-C -1 ; WX 500 ; N yacute ; B 16 -205 480 713 ;
-C -1 ; WX 444 ; N zacute ; B 21 0 420 713 ;
-C -1 ; WX 444 ; N zcaron ; B 21 0 420 704 ;
-C -1 ; WX 444 ; N zdotaccent ; B 21 0 420 666 ;
-C -1 ; WX 500 ; N ydieresis ; B 16 -205 480 666 ;
-C -1 ; WX 333 ; N tcommaaccent ; B 20 -341 332 630 ;
-C -1 ; WX 500 ; N amacron ; B 25 -14 488 637 ;
-C -1 ; WX 444 ; N emacron ; B 25 -14 426 637 ;
-C -1 ; WX 278 ; N imacron ; B -27 0 303 637 ;
-C -1 ; WX 556 ; N kcommaaccent ; B 22 -341 543 676 ;
-C -1 ; WX 278 ; N lcommaaccent ; B 16 -341 255 676 ;
-C -1 ; WX 556 ; N ncommaaccent ; B 21 -341 539 473 ;
-C -1 ; WX 500 ; N omacron ; B 25 -14 476 637 ;
-C -1 ; WX 444 ; N rcommaaccent ; B 29 -341 434 473 ;
-C -1 ; WX 556 ; N umacron ; B 16 -14 537 637 ;
-C -1 ; WX 556 ; N uogonek ; B 16 -173 556 461 ;
-C -1 ; WX 444 ; N rcaron ; B 29 0 434 704 ;
-C -1 ; WX 389 ; N scedilla ; B 25 -218 361 473 ;
-C -1 ; WX 500 ; N gcommaaccent ; B 28 -206 483 811 ;
-C -1 ; WX 278 ; N iogonek ; B 16 -173 388 691 ;
-C -1 ; WX 556 ; N Scommaaccent ; B 35 -341 513 692 ;
-C -1 ; WX 722 ; N Eth ; B 6 0 690 676 ;
-C -1 ; WX 722 ; N Dcroat ; B 6 0 690 676 ;
-C -1 ; WX 611 ; N Thorn ; B 16 0 600 676 ;
-C -1 ; WX 556 ; N dcroat ; B 25 -14 534 676 ;
-C -1 ; WX 500 ; N eth ; B 25 -14 476 691 ;
-C -1 ; WX 556 ; N thorn ; B 19 -205 524 676 ;
-C -1 ; WX 500 ; N Euro ; B -36 -24 478 671 ;
-C -1 ; WX 300 ; N onesuperior ; B 28 275 273 688 ;
-C -1 ; WX 300 ; N twosuperior ; B 0 275 300 688 ;
-C -1 ; WX 300 ; N threesuperior ; B 3 268 297 688 ;
-C -1 ; WX 400 ; N degree ; B 57 402 343 688 ;
-C -1 ; WX 570 ; N minus ; B 33 209 537 297 ;
-C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ;
-C -1 ; WX 570 ; N divide ; B 33 -31 537 537 ;
-C -1 ; WX 1000 ; N trademark ; B 24 271 977 676 ;
-C -1 ; WX 570 ; N plusminus ; B 33 0 537 568 ;
-C -1 ; WX 750 ; N onehalf ; B -7 -12 775 688 ;
-C -1 ; WX 750 ; N onequarter ; B 28 -12 743 688 ;
-C -1 ; WX 750 ; N threequarters ; B 23 -12 733 688 ;
-C -1 ; WX 333 ; N commaaccent ; B 84 -341 249 -40 ;
-C -1 ; WX 747 ; N copyright ; B 26 -19 721 691 ;
-C -1 ; WX 747 ; N registered ; B 26 -19 721 691 ;
-C -1 ; WX 494 ; N lozenge ; B 18 0 466 740 ;
-C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
-C -1 ; WX 570 ; N notequal ; B 33 -13 537 519 ;
-C -1 ; WX 549 ; N radical ; B -17 -35 535 916 ;
-C -1 ; WX 570 ; N lessequal ; B 31 0 539 642 ;
-C -1 ; WX 570 ; N greaterequal ; B 31 0 539 642 ;
-C -1 ; WX 570 ; N logicalnot ; B 33 108 537 399 ;
-C -1 ; WX 713 ; N summation ; B 14 -123 695 752 ;
-C -1 ; WX 494 ; N partialdiff ; B 16 -20 472 743 ;
-C -1 ; WX 220 ; N brokenbar ; B 66 -19 154 691 ;
-C -1 ; WX 556 ; N mu ; B 33 -206 536 461 ;
-C -1 ; WX 722 ; N afii10017 ; B 9 0 689 690 ;
-C -1 ; WX 667 ; N afii10018 ; B 16 0 619 676 ;
-C -1 ; WX 667 ; N afii10019 ; B 16 0 619 676 ;
-C -1 ; WX 591 ; N afii10020 ; B 16 0 563 676 ;
-C -1 ; WX 778 ; N afii10021 ; B 21 -200 759 676 ;
-C -1 ; WX 667 ; N afii10022 ; B 16 0 641 676 ;
-C -1 ; WX 667 ; N afii10023 ; B 16 0 641 855 ;
-C -1 ; WX 1107 ; N afii10024 ; B 35 0 1073 686 ;
-C -1 ; WX 564 ; N afii10025 ; B 14 -19 546 691 ;
-C -1 ; WX 773 ; N afii10026 ; B 16 0 754 676 ;
-C -1 ; WX 773 ; N afii10027 ; B 16 0 754 889 ;
-C -1 ; WX 764 ; N afii10028 ; B 16 0 718 686 ;
-C -1 ; WX 778 ; N afii10029 ; B 18 -14 744 676 ;
-C -1 ; WX 943 ; N afii10030 ; B 16 0 923 676 ;
-C -1 ; WX 774 ; N afii10031 ; B 16 0 754 676 ;
-C -1 ; WX 778 ; N afii10032 ; B 35 -19 743 691 ;
-C -1 ; WX 774 ; N afii10033 ; B 16 0 754 676 ;
-C -1 ; WX 611 ; N afii10034 ; B 16 0 600 676 ;
-C -1 ; WX 722 ; N afii10035 ; B 49 -19 687 691 ;
-C -1 ; WX 667 ; N afii10036 ; B 31 0 636 676 ;
-C -1 ; WX 722 ; N afii10037 ; B 15 -14 714 676 ;
-C -1 ; WX 800 ; N afii10038 ; B 12 0 784 676 ;
-C -1 ; WX 722 ; N afii10039 ; B 16 0 699 676 ;
-C -1 ; WX 773 ; N afii10040 ; B 16 -200 754 676 ;
-C -1 ; WX 778 ; N afii10041 ; B 21 0 759 676 ;
-C -1 ; WX 1113 ; N afii10042 ; B 16 0 1093 676 ;
-C -1 ; WX 1112 ; N afii10043 ; B 16 -200 1093 676 ;
-C -1 ; WX 867 ; N afii10044 ; B 85 0 807 676 ;
-C -1 ; WX 970 ; N afii10045 ; B 16 0 950 676 ;
-C -1 ; WX 630 ; N afii10046 ; B 16 0 600 676 ;
-C -1 ; WX 722 ; N afii10047 ; B 49 -19 687 691 ;
-C -1 ; WX 1114 ; N afii10048 ; B 16 -19 1067 691 ;
-C -1 ; WX 735 ; N afii10049 ; B 26 0 715 676 ;
-C -1 ; WX 500 ; N afii10065 ; B 25 -14 488 473 ;
-C -1 ; WX 500 ; N afii10066 ; B 28 -14 476 690 ;
-C -1 ; WX 502 ; N afii10067 ; B 21 0 464 461 ;
-C -1 ; WX 443 ; N afii10068 ; B 21 0 415 461 ;
-C -1 ; WX 556 ; N afii10069 ; B 17 -142 544 461 ;
-C -1 ; WX 444 ; N afii10070 ; B 25 -14 426 473 ;
-C -1 ; WX 444 ; N afii10071 ; B 25 -14 426 640 ;
-C -1 ; WX 750 ; N afii10072 ; B 12 0 735 470 ;
-C -1 ; WX 408 ; N afii10073 ; B 15 -14 383 473 ;
-C -1 ; WX 556 ; N afii10074 ; B 21 0 539 461 ;
-C -1 ; WX 556 ; N afii10075 ; B 21 0 539 674 ;
-C -1 ; WX 534 ; N afii10076 ; B 22 0 514 470 ;
-C -1 ; WX 544 ; N afii10077 ; B 7 -10 519 461 ;
-C -1 ; WX 676 ; N afii10078 ; B 21 -14 650 461 ;
-C -1 ; WX 556 ; N afii10079 ; B 21 0 539 461 ;
-C -1 ; WX 500 ; N afii10080 ; B 25 -14 476 473 ;
-C -1 ; WX 556 ; N afii10081 ; B 21 0 539 461 ;
-C -1 ; WX 556 ; N afii10082 ; B 19 -205 524 473 ;
-C -1 ; WX 444 ; N afii10083 ; B 25 -14 430 473 ;
-C -1 ; WX 494 ; N afii10084 ; B 12 0 475 461 ;
-C -1 ; WX 500 ; N afii10085 ; B 16 -205 480 461 ;
-C -1 ; WX 825 ; N afii10086 ; B 34 -205 793 683 ;
-C -1 ; WX 500 ; N afii10087 ; B 12 0 484 461 ;
-C -1 ; WX 556 ; N afii10088 ; B 21 -142 540 461 ;
-C -1 ; WX 556 ; N afii10089 ; B 27 0 539 461 ;
-C -1 ; WX 818 ; N afii10090 ; B 21 0 803 461 ;
-C -1 ; WX 818 ; N afii10091 ; B 21 -142 804 461 ;
-C -1 ; WX 612 ; N afii10092 ; B 12 0 590 461 ;
-C -1 ; WX 762 ; N afii10093 ; B 21 0 739 461 ;
-C -1 ; WX 512 ; N afii10094 ; B 21 0 490 461 ;
-C -1 ; WX 444 ; N afii10095 ; B 29 -14 427 473 ;
-C -1 ; WX 790 ; N afii10096 ; B 29 -14 753 473 ;
-C -1 ; WX 512 ; N afii10097 ; B 12 0 490 461 ;
-C -1 ; WX 667 ; N uni0400 ; B 16 0 641 911 ;
-C -1 ; WX 932 ; N afii10051 ; B 31 -148 818 676 ;
-C -1 ; WX 611 ; N afii10052 ; B 16 0 583 911 ;
-C -1 ; WX 722 ; N afii10053 ; B 49 -19 687 691 ;
-C -1 ; WX 556 ; N afii10054 ; B 35 -19 513 692 ;
-C -1 ; WX 389 ; N afii10055 ; B 16 0 366 676 ;
-C -1 ; WX 389 ; N afii10056 ; B 16 0 366 855 ;
-C -1 ; WX 500 ; N afii10057 ; B 3 -96 479 676 ;
-C -1 ; WX 1032 ; N afii10058 ; B 18 -14 1003 676 ;
-C -1 ; WX 1032 ; N afii10059 ; B 21 0 1003 676 ;
-C -1 ; WX 932 ; N afii10060 ; B 31 0 903 676 ;
-C -1 ; WX 778 ; N afii10061 ; B 30 0 732 911 ;
-C -1 ; WX 778 ; N uni040D ; B 21 0 759 911 ;
-C -1 ; WX 722 ; N afii10062 ; B 15 -14 714 889 ;
-C -1 ; WX 778 ; N afii10145 ; B 21 -228 759 676 ;
-C -1 ; WX 444 ; N uni0450 ; B 25 -14 426 696 ;
-C -1 ; WX 556 ; N afii10099 ; B 13 -203 485 676 ;
-C -1 ; WX 458 ; N afii10100 ; B 21 0 430 696 ;
-C -1 ; WX 444 ; N afii10101 ; B 25 -14 430 473 ;
-C -1 ; WX 389 ; N afii10102 ; B 25 -14 361 473 ;
-C -1 ; WX 278 ; N afii10103 ; B 16 0 255 691 ;
-C -1 ; WX 278 ; N afii10104 ; B -34 0 305 640 ;
-C -1 ; WX 333 ; N afii10105 ; B -57 -203 263 691 ;
-C -1 ; WX 792 ; N afii10106 ; B 7 -10 773 461 ;
-C -1 ; WX 786 ; N afii10107 ; B 21 0 773 461 ;
-C -1 ; WX 556 ; N afii10108 ; B 13 0 534 676 ;
-C -1 ; WX 534 ; N afii10109 ; B 22 0 514 696 ;
-C -1 ; WX 556 ; N uni045D ; B 21 0 539 696 ;
-C -1 ; WX 500 ; N afii10110 ; B 16 -205 480 674 ;
-C -1 ; WX 556 ; N afii10193 ; B 21 -179 539 461 ;
-C -1 ; WX 611 ; N uni048C ; B 16 0 600 676 ;
-C -1 ; WX 512 ; N uni048D ; B 17 0 490 461 ;
-C -1 ; WX 611 ; N uni048E ; B 16 0 600 676 ;
-C -1 ; WX 556 ; N uni048F ; B 19 -205 525 473 ;
-C -1 ; WX 611 ; N afii10050 ; B 16 0 584 842 ;
-C -1 ; WX 458 ; N afii10098 ; B 21 0 430 571 ;
-C -1 ; WX 611 ; N uni0492 ; B 16 0 583 676 ;
-C -1 ; WX 458 ; N uni0493 ; B 21 0 430 461 ;
-C -1 ; WX 611 ; N uni0494 ; B 16 -203 583 676 ;
-C -1 ; WX 458 ; N uni0495 ; B 21 -204 532 461 ;
-C -1 ; WX 1107 ; N uni0496 ; B 35 -167 1084 686 ;
-C -1 ; WX 750 ; N uni0497 ; B 12 -110 741 470 ;
-C -1 ; WX 564 ; N uni0498 ; B 14 -197 546 691 ;
-C -1 ; WX 408 ; N uni0499 ; B 15 -197 383 473 ;
-C -1 ; WX 778 ; N uni049A ; B 30 -167 743 686 ;
-C -1 ; WX 534 ; N uni049B ; B 22 -110 517 470 ;
-C -1 ; WX 778 ; N uni049C ; B 30 0 731 686 ;
-C -1 ; WX 534 ; N uni049D ; B 22 0 514 470 ;
-C -1 ; WX 778 ; N uni049E ; B 31 0 734 686 ;
-C -1 ; WX 534 ; N uni049F ; B 16 0 514 470 ;
-C -1 ; WX 967 ; N uni04A0 ; B 85 0 921 686 ;
-C -1 ; WX 633 ; N uni04A1 ; B 12 0 613 470 ;
-C -1 ; WX 778 ; N uni04A2 ; B 21 -167 759 676 ;
-C -1 ; WX 556 ; N uni04A3 ; B 21 -110 544 461 ;
-C -1 ; WX 1014 ; N uni04A4 ; B 21 0 986 676 ;
-C -1 ; WX 735 ; N uni04A5 ; B 21 0 707 461 ;
-C -1 ; WX 978 ; N uni04A6 ; B 21 -203 948 676 ;
-C -1 ; WX 830 ; N uni04A7 ; B 21 -204 809 461 ;
-C -1 ; WX 760 ; N uni04A8 ; B 49 -19 736 691 ;
-C -1 ; WX 484 ; N uni04A9 ; B 25 -14 472 473 ;
-C -1 ; WX 722 ; N uni04AA ; B 49 -197 687 691 ;
-C -1 ; WX 444 ; N uni04AB ; B 25 -197 430 473 ;
-C -1 ; WX 667 ; N uni04AC ; B 31 -167 636 676 ;
-C -1 ; WX 494 ; N uni04AD ; B 12 -110 475 461 ;
-C -1 ; WX 722 ; N uni04AE ; B 15 0 699 676 ;
-C -1 ; WX 500 ; N uni04AF ; B 21 -225 485 461 ;
-C -1 ; WX 722 ; N uni04B0 ; B 15 0 699 676 ;
-C -1 ; WX 500 ; N uni04B1 ; B 21 -225 485 461 ;
-C -1 ; WX 722 ; N uni04B2 ; B 16 -167 716 676 ;
-C -1 ; WX 500 ; N uni04B3 ; B 12 -110 496 461 ;
-C -1 ; WX 1046 ; N uni04B4 ; B 31 -167 1027 676 ;
-C -1 ; WX 778 ; N uni04B5 ; B 12 -110 759 461 ;
-C -1 ; WX 778 ; N uni04B6 ; B 21 -167 759 676 ;
-C -1 ; WX 556 ; N uni04B7 ; B 27 -110 544 461 ;
-C -1 ; WX 778 ; N uni04B8 ; B 21 0 759 676 ;
-C -1 ; WX 556 ; N uni04B9 ; B 27 0 539 461 ;
-C -1 ; WX 778 ; N uni04BA ; B 21 0 759 676 ;
-C -1 ; WX 556 ; N uni04BB ; B 27 0 539 461 ;
-C -1 ; WX 865 ; N uni04BC ; B 29 -19 868 688 ;
-C -1 ; WX 566 ; N uni04BD ; B 17 -14 548 473 ;
-C -1 ; WX 865 ; N uni04BE ; B 29 -197 868 688 ;
-C -1 ; WX 566 ; N uni04BF ; B 17 -197 548 473 ;
-C -1 ; WX 389 ; N uni04C0 ; B 16 0 366 676 ;
-C -1 ; WX 1107 ; N uni04C1 ; B 35 0 1073 889 ;
-C -1 ; WX 750 ; N uni04C2 ; B 12 0 735 674 ;
-C -1 ; WX 724 ; N uni04C3 ; B 30 -205 678 686 ;
-C -1 ; WX 534 ; N uni04C4 ; B 22 -204 507 470 ;
-C -1 ; WX 778 ; N uni04C7 ; B 21 -236 759 676 ;
-C -1 ; WX 556 ; N uni04C8 ; B 21 -203 539 461 ;
-C -1 ; WX 778 ; N uni04CB ; B 21 -167 759 676 ;
-C -1 ; WX 556 ; N uni04CC ; B 27 -110 539 461 ;
-C -1 ; WX 722 ; N uni04D0 ; B 9 0 689 889 ;
-C -1 ; WX 500 ; N uni04D1 ; B 25 -14 488 674 ;
-C -1 ; WX 722 ; N uni04D2 ; B 9 0 689 855 ;
-C -1 ; WX 500 ; N uni04D3 ; B 25 -14 488 640 ;
-C -1 ; WX 1000 ; N uni04D4 ; B 4 0 951 676 ;
-C -1 ; WX 722 ; N uni04D5 ; B 33 -14 693 473 ;
-C -1 ; WX 667 ; N uni04D6 ; B 16 0 641 889 ;
-C -1 ; WX 444 ; N uni04D7 ; B 25 -14 426 674 ;
-C -1 ; WX 660 ; N uni04D8 ; B 29 -19 663 688 ;
-C -1 ; WX 444 ; N afii10846 ; B 25 -14 426 473 ;
-C -1 ; WX 660 ; N uni04DA ; B 29 -19 663 840 ;
-C -1 ; WX 444 ; N uni04DB ; B 25 -14 426 640 ;
-C -1 ; WX 1107 ; N uni04DC ; B 35 0 1073 865 ;
-C -1 ; WX 750 ; N uni04DD ; B 12 0 735 650 ;
-C -1 ; WX 564 ; N uni04DE ; B 14 -19 546 840 ;
-C -1 ; WX 408 ; N uni04DF ; B 15 -14 383 622 ;
-C -1 ; WX 580 ; N uni04E0 ; B 13 -19 560 692 ;
-C -1 ; WX 389 ; N uni04E1 ; B 16 -14 368 471 ;
-C -1 ; WX 778 ; N uni04E2 ; B 21 0 759 798 ;
-C -1 ; WX 556 ; N uni04E3 ; B 21 0 539 583 ;
-C -1 ; WX 778 ; N uni04E4 ; B 21 0 759 855 ;
-C -1 ; WX 556 ; N uni04E5 ; B 21 0 539 640 ;
-C -1 ; WX 778 ; N uni04E6 ; B 35 -19 743 855 ;
-C -1 ; WX 500 ; N uni04E7 ; B 25 -14 476 640 ;
-C -1 ; WX 778 ; N uni04E8 ; B 35 -19 743 691 ;
-C -1 ; WX 500 ; N uni04E9 ; B 25 -14 476 473 ;
-C -1 ; WX 778 ; N uni04EA ; B 35 -19 743 855 ;
-C -1 ; WX 500 ; N uni04EB ; B 25 -14 476 640 ;
-C -1 ; WX 722 ; N uni04EC ; B 49 -19 687 855 ;
-C -1 ; WX 444 ; N uni04ED ; B 25 -14 430 640 ;
-C -1 ; WX 722 ; N uni04EE ; B 15 -14 714 798 ;
-C -1 ; WX 500 ; N uni04EF ; B 16 -205 480 583 ;
-C -1 ; WX 722 ; N uni04F0 ; B 15 -14 714 855 ;
-C -1 ; WX 500 ; N uni04F1 ; B 16 -205 480 640 ;
-C -1 ; WX 722 ; N uni04F2 ; B 15 -14 714 911 ;
-C -1 ; WX 500 ; N uni04F3 ; B 16 -205 480 696 ;
-C -1 ; WX 778 ; N uni04F4 ; B 21 0 759 855 ;
-C -1 ; WX 556 ; N uni04F5 ; B 27 0 539 640 ;
-C -1 ; WX 987 ; N uni04F8 ; B 16 0 970 855 ;
-C -1 ; WX 762 ; N uni04F9 ; B 21 0 739 640 ;
-C -1 ; WX 443 ; N uniF6C4 ; B 21 0 415 461 ;
-C -1 ; WX 500 ; N uniF6C5 ; B 24 -14 476 690 ;
-C -1 ; WX 556 ; N uniF6C6 ; B 17 -142 544 461 ;
-C -1 ; WX 556 ; N uniF6C7 ; B 21 0 539 461 ;
-C -1 ; WX 494 ; N uniF6C8 ; B 12 0 475 461 ;
-C -1 ; WX 722 ; N Ccircumflex ; B 49 -19 687 902 ;
-C -1 ; WX 444 ; N ccircumflex ; B 25 -14 430 687 ;
-C -1 ; WX 722 ; N Cdotaccent ; B 49 -19 687 855 ;
-C -1 ; WX 444 ; N cdotaccent ; B 25 -14 430 640 ;
-C -1 ; WX 667 ; N Ebreve ; B 16 0 641 889 ;
-C -1 ; WX 444 ; N ebreve ; B 25 -14 426 674 ;
-C -1 ; WX 778 ; N Gcircumflex ; B 37 -19 755 902 ;
-C -1 ; WX 500 ; N gcircumflex ; B 28 -206 483 687 ;
-C -1 ; WX 778 ; N Gdotaccent ; B 37 -19 755 855 ;
-C -1 ; WX 500 ; N gdotaccent ; B 28 -206 483 640 ;
-C -1 ; WX 778 ; N Hcircumflex ; B 16 0 754 902 ;
-C -1 ; WX 556 ; N hcircumflex ; B 2 0 534 902 ;
-C -1 ; WX 778 ; N Hbar ; B 21 0 759 676 ;
-C -1 ; WX 556 ; N hbar ; B 13 0 534 676 ;
-C -1 ; WX 389 ; N Itilde ; B 8 0 373 853 ;
-C -1 ; WX 278 ; N itilde ; B -47 0 318 638 ;
-C -1 ; WX 389 ; N Ibreve ; B 16 0 366 889 ;
-C -1 ; WX 278 ; N ibreve ; B -16 0 287 674 ;
-C -1 ; WX 882 ; N IJ ; B 16 -96 869 676 ;
-C -1 ; WX 486 ; N ij ; B 16 -203 463 691 ;
-C -1 ; WX 500 ; N Jcircumflex ; B 3 -96 479 902 ;
-C -1 ; WX 333 ; N jcircumflex ; B -56 -203 335 768 ;
-C -1 ; WX 534 ; N kgreenlandic ; B 22 0 514 470 ;
-C -1 ; WX 667 ; N Ldot ; B 16 0 635 676 ;
-C -1 ; WX 528 ; N ldot ; B 16 0 488 676 ;
-C -1 ; WX 704 ; N napostrophe ; B 21 0 687 582 ;
-C -1 ; WX 722 ; N Eng ; B 16 -228 701 676 ;
-C -1 ; WX 556 ; N eng ; B 21 -203 490 473 ;
-C -1 ; WX 778 ; N Obreve ; B 35 -19 743 889 ;
-C -1 ; WX 500 ; N obreve ; B 25 -14 476 674 ;
-C -1 ; WX 556 ; N Scircumflex ; B 35 -19 513 902 ;
-C -1 ; WX 389 ; N scircumflex ; B 24 -14 361 687 ;
-C -1 ; WX 667 ; N Tbar ; B 32 0 637 676 ;
-C -1 ; WX 333 ; N tbar ; B 13 -12 332 630 ;
-C -1 ; WX 722 ; N Utilde ; B 16 -19 701 853 ;
-C -1 ; WX 556 ; N utilde ; B 16 -14 537 638 ;
-C -1 ; WX 722 ; N Ubreve ; B 16 -19 701 889 ;
-C -1 ; WX 556 ; N ubreve ; B 16 -14 537 674 ;
-C -1 ; WX 1000 ; N Wcircumflex ; B 19 -15 981 902 ;
-C -1 ; WX 722 ; N wcircumflex ; B 23 -14 707 687 ;
-C -1 ; WX 722 ; N Ycircumflex ; B 15 0 699 902 ;
-C -1 ; WX 500 ; N ycircumflex ; B 16 -205 480 687 ;
-C -1 ; WX 333 ; N longs ; B 14 0 389 691 ;
-C -1 ; WX 954 ; N afii61352 ; B 11 -25 936 681 ;
-C -1 ; WX 752 ; N infinity ; B 22 42 723 456 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 983
-KPX quoteright y -22
-KPX quoteright w -23
-KPX quoteright v -25
-KPX quoteright t -19
-KPX quoteright s -17
-KPX quoteright r -26
-KPX quoteright period -35
-KPX quoteright o -34
-KPX quoteright d -31
-KPX quoteright comma -34
-KPX quoteright Aring -91
-KPX quoteright Adieresis -91
-KPX quoteright Aacute -91
-KPX quoteright AE -110
-KPX quoteright A -91
-KPX comma quoteright -23
-KPX comma quotedblright 9
-KPX comma one -12
-KPX hyphen Y -83
-KPX hyphen W -54
-KPX hyphen V -72
-KPX hyphen T -74
-KPX hyphen Aring -18
-KPX hyphen Adieresis -18
-KPX hyphen Aacute -18
-KPX hyphen AE -24
-KPX hyphen A -18
-KPX period quoteright -27
-KPX period quotedblright 5
-KPX period one -21
-KPX zero seven 7
-KPX zero one -31
-KPX zero four 11
-KPX one zero -35
-KPX one two -2
-KPX one three -10
-KPX one six -47
-KPX one seven -56
-KPX one period -17
-KPX one one -27
-KPX one nine -9
-KPX one four -56
-KPX one five -16
-KPX one eight -34
-KPX one comma -16
-KPX two seven -7
-KPX two one -29
-KPX two four 14
-KPX three seven -15
-KPX three one -33
-KPX three four 9
-KPX four seven -16
-KPX four one -35
-KPX four four 13
-KPX five seven -9
-KPX five one -28
-KPX five four 1
-KPX six seven -7
-KPX six one -43
-KPX six four 13
-KPX seven two -21
-KPX seven three -20
-KPX seven six -37
-KPX seven seven -6
-KPX seven period -58
-KPX seven one -25
-KPX seven four -54
-KPX seven five -34
-KPX seven eight -18
-KPX seven comma -57
-KPX seven colon -64
-KPX eight one -19
-KPX eight four 11
-KPX nine seven 10
-KPX nine one -26
-KPX nine four 2
-KPX A y -83
-KPX A w -79
-KPX A v -84
-KPX A u -30
-KPX A t -27
-KPX A quoteright -108
-KPX A quotedblright -76
-KPX A q -38
-KPX A o -37
-KPX A hyphen -30
-KPX A guilsinglleft -67
-KPX A guillemotleft -53
-KPX A g -7
-KPX A e -32
-KPX A d -28
-KPX A comma 1
-KPX A ccedilla -43
-KPX A c -35
-KPX A b -22
-KPX A a -5
-KPX A Y -74
-KPX A W -116
-KPX A V -130
-KPX A Ugrave -66
-KPX A Udieresis -66
-KPX A Ucircumflex -66
-KPX A Uacute -66
-KPX A U -66
-KPX A T -59
-KPX A Q -68
-KPX A Odieresis -68
-KPX A O -68
-KPX A G -68
-KPX A Ccedilla -77
-KPX A C -73
-KPX B Y -44
-KPX B W -46
-KPX B V -45
-KPX B Oslash -11
-KPX B Ograve -12
-KPX B Odieresis -12
-KPX B Ocircumflex -12
-KPX B Oacute -12
-KPX B OE -4
-KPX B O -12
-KPX B Atilde -34
-KPX B Aring -34
-KPX B Adieresis -34
-KPX B Acircumflex -34
-KPX B Aacute -34
-KPX B AE -32
-KPX B A -34
-KPX C Odieresis -14
-KPX C Oacute -14
-KPX C O -14
-KPX C K -6
-KPX C H -2
-KPX C Aring -25
-KPX C Adieresis -25
-KPX C Aacute -25
-KPX C AE -22
-KPX C A -25
-KPX D Y -59
-KPX D X -51
-KPX D W -50
-KPX D V -60
-KPX D T -7
-KPX D J -40
-KPX D Atilde -55
-KPX D Aring -55
-KPX D Agrave -55
-KPX D Adieresis -55
-KPX D Acircumflex -55
-KPX D Aacute -55
-KPX D A -55
-KPX F u -10
-KPX F r -7
-KPX F period -60
-KPX F oslash -53
-KPX F oe -51
-KPX F odieresis -24
-KPX F oacute -54
-KPX F o -54
-KPX F j -26
-KPX F i -1
-KPX F hyphen -34
-KPX F eacute -51
-KPX F e -51
-KPX F comma -59
-KPX F aring -50
-KPX F ae -53
-KPX F adieresis -22
-KPX F aacute -50
-KPX F a -50
-KPX F Odieresis -7
-KPX F O -7
-KPX F J -42
-KPX F Atilde -79
-KPX F Aring -79
-KPX F Agrave -79
-KPX F Adieresis -79
-KPX F Acircumflex -79
-KPX F Aacute -79
-KPX F A -79
-KPX G Y -33
-KPX G W -35
-KPX G V -33
-KPX G T -41
-KPX G Atilde -27
-KPX G Aring -27
-KPX G Agrave -27
-KPX G Adieresis -27
-KPX G Acircumflex -27
-KPX G Aacute -27
-KPX G AE -24
-KPX G A -27
-KPX J Aring -30
-KPX J Adieresis -30
-KPX J AE -27
-KPX J A -30
-KPX K y -83
-KPX K udieresis -18
-KPX K u -18
-KPX K odieresis -25
-KPX K oacute -25
-KPX K o -25
-KPX K hyphen -47
-KPX K e -20
-KPX K aring 6
-KPX K ae 3
-KPX K adieresis 6
-KPX K a 6
-KPX K T -2
-KPX K S 13
-KPX K Odieresis -56
-KPX K Oacute -56
-KPX K OE -46
-KPX K O -56
-KPX K G -56
-KPX K C -61
-KPX L y -49
-KPX L udieresis -12
-KPX L u -11
-KPX L quoteright -69
-KPX L quotedblright -37
-KPX L hyphen 24
-KPX L Y -89
-KPX L W -87
-KPX L V -106
-KPX L Udieresis -29
-KPX L U -29
-KPX L T -74
-KPX L S 2
-KPX L Otilde -5
-KPX L Ograve -5
-KPX L Odieresis -5
-KPX L Ocircumflex -5
-KPX L Oacute -5
-KPX L O -5
-KPX L G -5
-KPX L Ccedilla -14
-KPX L C -11
-KPX L Aring -1
-KPX L Adieresis -1
-KPX L Aacute -1
-KPX L AE 1
-KPX L A -1
-KPX N udieresis -17
-KPX N u -17
-KPX N oslash -15
-KPX N odieresis -16
-KPX N oacute -16
-KPX N o -16
-KPX N eacute -13
-KPX N e -13
-KPX N comma 1
-KPX N aring -16
-KPX N ae -18
-KPX N adieresis -16
-KPX N aacute -16
-KPX N a -16
-KPX N Odieresis -15
-KPX N Oacute -15
-KPX N O -15
-KPX N G -16
-KPX N Ccedilla -22
-KPX N C -22
-KPX N Aring -19
-KPX N Adieresis -19
-KPX N Aacute -19
-KPX N AE -16
-KPX N A -19
-KPX O Y -59
-KPX O X -51
-KPX O W -54
-KPX O V -60
-KPX O T -9
-KPX O Aring -55
-KPX O Adieresis -55
-KPX O Aacute -55
-KPX O AE -54
-KPX O A -55
-KPX P period -86
-KPX P oslash -33
-KPX P oe -30
-KPX P odieresis -22
-KPX P oacute -33
-KPX P o -33
-KPX P hyphen -39
-KPX P eacute -29
-KPX P e -29
-KPX P comma -85
-KPX P aring -19
-KPX P ae -22
-KPX P adieresis -19
-KPX P aacute -19
-KPX P a -19
-KPX P J -68
-KPX P Aring -81
-KPX P Adieresis -81
-KPX P Aacute -81
-KPX P AE -94
-KPX P A -81
-KPX R y -27
-KPX R udieresis -17
-KPX R uacute -17
-KPX R u -17
-KPX R oe -21
-KPX R odieresis -24
-KPX R oacute -24
-KPX R o -24
-KPX R hyphen -30
-KPX R eacute -19
-KPX R e -19
-KPX R aring 7
-KPX R ae 4
-KPX R adieresis 7
-KPX R aacute 7
-KPX R a 7
-KPX R Y -53
-KPX R W -55
-KPX R V -53
-KPX R Udieresis -37
-KPX R U -37
-KPX R T -26
-KPX R Odieresis -29
-KPX R Oacute -29
-KPX R OE -22
-KPX R O -29
-KPX R G -30
-KPX R Ccedilla -37
-KPX R C -36
-KPX S t -10
-KPX S Y -8
-KPX S W -10
-KPX S V -9
-KPX S T -16
-KPX S Aring -24
-KPX S Adieresis -24
-KPX S Aacute -24
-KPX S AE -21
-KPX S A -24
-KPX T y -104
-KPX T w -107
-KPX T v -106
-KPX T u -89
-KPX T semicolon -85
-KPX T s -59
-KPX T r -61
-KPX T period -64
-KPX T oslash -87
-KPX T o -88
-KPX T j -40
-KPX T i -16
-KPX T hyphen -73
-KPX T guilsinglleft -113
-KPX T guillemotleft -99
-KPX T g -68
-KPX T e -85
-KPX T comma -63
-KPX T colon -85
-KPX T c -88
-KPX T ae -69
-KPX T a -65
-KPX T Y 11
-KPX T W 9
-KPX T V 11
-KPX T S -2
-KPX T Otilde -9
-KPX T Oslash -11
-KPX T Ograve -9
-KPX T Odieresis -9
-KPX T Ocircumflex -9
-KPX T Oacute -9
-KPX T OE -3
-KPX T O -9
-KPX T J -43
-KPX T G -11
-KPX T C -17
-KPX T Atilde -46
-KPX T Aring -46
-KPX T Agrave -46
-KPX T Adieresis -46
-KPX T Acircumflex -46
-KPX T Aacute -46
-KPX T AE -44
-KPX T A -46
-KPX U r -29
-KPX U period -18
-KPX U p -28
-KPX U n -25
-KPX U m -23
-KPX U comma -17
-KPX U Atilde -54
-KPX U Aring -54
-KPX U Adieresis -54
-KPX U Acircumflex -54
-KPX U Aacute -54
-KPX U AE -52
-KPX U A -54
-KPX V y -56
-KPX V u -58
-KPX V semicolon -94
-KPX V r -60
-KPX V period -95
-KPX V oslash -87
-KPX V o -89
-KPX V i -13
-KPX V hyphen -68
-KPX V guilsinglleft -112
-KPX V guillemotleft -98
-KPX V g -86
-KPX V e -86
-KPX V comma -94
-KPX V colon -94
-KPX V ae -90
-KPX V a -87
-KPX V T 8
-KPX V S -25
-KPX V Otilde -63
-KPX V Oslash -65
-KPX V Ograve -63
-KPX V Odieresis -63
-KPX V Ocircumflex -63
-KPX V Oacute -63
-KPX V O -63
-KPX V G -64
-KPX V C -70
-KPX V Atilde -113
-KPX V Aring -113
-KPX V Agrave -113
-KPX V Adieresis -113
-KPX V Acircumflex -113
-KPX V Aacute -113
-KPX V AE -113
-KPX V A -113
-KPX W y -44
-KPX W u -45
-KPX W semicolon -80
-KPX W r -49
-KPX W period -73
-KPX W oslash -69
-KPX W o -70
-KPX W i -12
-KPX W hyphen -49
-KPX W guilsinglleft -93
-KPX W guillemotleft -79
-KPX W g -70
-KPX W e -67
-KPX W comma -72
-KPX W colon -81
-KPX W ae -73
-KPX W a -70
-KPX W T 9
-KPX W S -24
-KPX W Otilde -51
-KPX W Oslash -50
-KPX W Ograve -51
-KPX W Odieresis -51
-KPX W Ocircumflex -51
-KPX W Oacute -51
-KPX W O -51
-KPX W G -52
-KPX W C -58
-KPX W Atilde -98
-KPX W Aring -98
-KPX W Agrave -98
-KPX W Adieresis -98
-KPX W Acircumflex -98
-KPX W Aacute -98
-KPX W AE -102
-KPX W A -98
-KPX X y -90
-KPX X u -25
-KPX X o -32
-KPX X hyphen -43
-KPX X e -27
-KPX X Q -57
-KPX X Odieresis -56
-KPX X O -56
-KPX X C -63
-KPX Y v -78
-KPX Y u -76
-KPX Y semicolon -103
-KPX Y period -81
-KPX Y p -72
-KPX Y oslash -95
-KPX Y o -96
-KPX Y i -14
-KPX Y hyphen -87
-KPX Y guilsinglleft -125
-KPX Y guillemotleft -111
-KPX Y g -86
-KPX Y e -93
-KPX Y comma -80
-KPX Y colon -103
-KPX Y ae -87
-KPX Y a -83
-KPX Y T 7
-KPX Y S -26
-KPX Y Otilde -64
-KPX Y Oslash -68
-KPX Y Ograve -64
-KPX Y Odieresis -64
-KPX Y Ocircumflex -64
-KPX Y Oacute -64
-KPX Y O -64
-KPX Y G -65
-KPX Y C -71
-KPX Y Atilde -64
-KPX Y Aring -64
-KPX Y Agrave -64
-KPX Y Adieresis -64
-KPX Y Acircumflex -64
-KPX Y Aacute -64
-KPX Y AE -62
-KPX Y A -64
-KPX Z y -44
-KPX Z v -45
-KPX quoteleft Y -17
-KPX quoteleft W -19
-KPX quoteleft V -17
-KPX quoteleft T -22
-KPX quoteleft Aring -92
-KPX quoteleft Adieresis -92
-KPX quoteleft Aacute -92
-KPX quoteleft AE -111
-KPX quoteleft A -92
-KPX a y -44
-KPX a w -40
-KPX a v -39
-KPX a quoteright -34
-KPX a j -39
-KPX b y -42
-KPX b w -40
-KPX b v -39
-KPX c k -18
-KPX c h -17
-KPX e y -31
-KPX e x -19
-KPX e w -30
-KPX e v -29
-KPX e t -10
-KPX e quoteright -19
-KPX f t -3
-KPX f s -8
-KPX f quoteright 18
-KPX f oslash -31
-KPX f oe -29
-KPX f odieresis 11
-KPX f oacute -32
-KPX f o -32
-KPX f l 33
-KPX f j -1
-KPX f i 22
-KPX f f 12
-KPX f eacute -29
-KPX f e -29
-KPX f aring -15
-KPX f ae -21
-KPX f adieresis 14
-KPX f aacute -17
-KPX f a -17
-KPX g r 1
-KPX g odieresis -20
-KPX g oacute -20
-KPX g eacute -20
-KPX g e -20
-KPX g aring -15
-KPX g ae -18
-KPX g adieresis -15
-KPX g a -15
-KPX h y -34
-KPX h quoteright -30
-KPX i j -36
-KPX i T -18
-KPX k udieresis -5
-KPX k u -5
-KPX k s 5
-KPX k odieresis -38
-KPX k oacute -38
-KPX k o -38
-KPX k hyphen -47
-KPX k g -4
-KPX k eacute -33
-KPX k e -33
-KPX k aring -3
-KPX k ae -7
-KPX k adieresis -3
-KPX k aacute -3
-KPX k a -3
-KPX l y -19
-KPX l v -22
-KPX m y -33
-KPX m w -33
-KPX m v -32
-KPX m p -16
-KPX n y -32
-KPX n w -32
-KPX n v -31
-KPX n quoteright -28
-KPX n p -14
-KPX n T -56
-KPX o y -42
-KPX o x -29
-KPX o w -38
-KPX o v -42
-KPX o t -10
-KPX o quoteright -27
-KPX o T -88
-KPX p y -34
-KPX p t -11
-KPX q u -15
-KPX q c -13
-KPX r z -1
-KPX r y 9
-KPX r x 11
-KPX r w 7
-KPX r v 8
-KPX r u 9
-KPX r t 9
-KPX r semicolon -16
-KPX r quoteright -8
-KPX r q -15
-KPX r period -68
-KPX r p 4
-KPX r oslash -14
-KPX r ograve -14
-KPX r oe -12
-KPX r odieresis -14
-KPX r ocircumflex -14
-KPX r oacute -14
-KPX r o -14
-KPX r n 4
-KPX r m 6
-KPX r l -14
-KPX r k -15
-KPX r j -12
-KPX r i 6
-KPX r hyphen -18
-KPX r h -15
-KPX r g -5
-KPX r f 11
-KPX r egrave -11
-KPX r ecircumflex -11
-KPX r eacute -11
-KPX r e -11
-KPX r d -13
-KPX r comma -67
-KPX r colon -16
-KPX r ccedilla -10
-KPX r c -15
-KPX r aring -6
-KPX r agrave -6
-KPX r ae -8
-KPX r adieresis -6
-KPX r acircumflex -6
-KPX r aacute -6
-KPX r a -6
-KPX s t -7
-KPX s quoteright -17
-KPX t semicolon -12
-KPX t quoteright -31
-KPX t odieresis -4
-KPX t oacute -4
-KPX t o -4
-KPX t h -4
-KPX t eacute -1
-KPX t e -1
-KPX t colon -12
-KPX t aring 11
-KPX t ae 7
-KPX t adieresis 11
-KPX t aacute 11
-KPX t a 11
-KPX t S 11
-KPX u quoteright -25
-KPX v semicolon -23
-KPX v s -16
-KPX v period -57
-KPX v oslash -39
-KPX v ograve -40
-KPX v odieresis -40
-KPX v oacute -40
-KPX v o -40
-KPX v l -16
-KPX v hyphen -27
-KPX v g -22
-KPX v egrave -35
-KPX v ecircumflex -35
-KPX v eacute -35
-KPX v e -35
-KPX v comma -56
-KPX v colon -23
-KPX v c -40
-KPX v atilde -23
-KPX v aring -23
-KPX v agrave -23
-KPX v ae -25
-KPX v adieresis -23
-KPX v acircumflex -23
-KPX v aacute -23
-KPX v a -23
-KPX w semicolon -23
-KPX w s -16
-KPX w period -51
-KPX w oslash -35
-KPX w ograve -36
-KPX w odieresis -36
-KPX w oacute -36
-KPX w o -36
-KPX w l -16
-KPX w hyphen -23
-KPX w g -22
-KPX w egrave -33
-KPX w ecircumflex -33
-KPX w eacute -33
-KPX w e -33
-KPX w comma -50
-KPX w colon -23
-KPX w c -36
-KPX w atilde -23
-KPX w aring -23
-KPX w agrave -23
-KPX w ae -25
-KPX w adieresis -23
-KPX w acircumflex -23
-KPX w aacute -23
-KPX w a -23
-KPX x q -32
-KPX x o -30
-KPX x eacute -27
-KPX x e -27
-KPX x c -30
-KPX x a -2
-KPX y semicolon -28
-KPX y s -24
-KPX y period -57
-KPX y oslash -41
-KPX y ograve -42
-KPX y odieresis -42
-KPX y oacute -42
-KPX y o -42
-KPX y l -19
-KPX y hyphen -29
-KPX y g -31
-KPX y egrave -40
-KPX y ecircumflex -40
-KPX y eacute -40
-KPX y e -40
-KPX y comma -56
-KPX y colon -28
-KPX y c -42
-KPX y atilde -32
-KPX y aring -32
-KPX y agrave -32
-KPX y ae -34
-KPX y adieresis -32
-KPX y acircumflex -32
-KPX y aacute -32
-KPX y a -32
-KPX quotedblleft Y 15
-KPX quotedblleft W 13
-KPX quotedblleft V 15
-KPX quotedblleft T 9
-KPX quotedblleft Aring -59
-KPX quotedblleft Adieresis -59
-KPX quotedblleft Aacute -59
-KPX quotedblleft AE -78
-KPX quotedblleft A -59
-KPX guilsinglright Y -120
-KPX guilsinglright W -98
-KPX guilsinglright V -116
-KPX guilsinglright T -114
-KPX guilsinglright Aring -54
-KPX guilsinglright Adieresis -54
-KPX guilsinglright Aacute -54
-KPX guilsinglright AE -60
-KPX guilsinglright A -54
-KPX quotedblbase Y -73
-KPX quotedblbase W -75
-KPX quotedblbase V -98
-KPX quotedblbase T -59
-KPX quotedblbase AE 20
-KPX quotedblbase A 19
-KPX quotedblright Y 6
-KPX quotedblright W 4
-KPX quotedblright V 5
-KPX quotedblright T 4
-KPX quotedblright Aring -72
-KPX quotedblright Adieresis -72
-KPX quotedblright Aacute -72
-KPX quotedblright AE -91
-KPX quotedblright A -72
-KPX guillemotright Y -106
-KPX guillemotright W -84
-KPX guillemotright V -102
-KPX guillemotright T -100
-KPX guillemotright Aring -40
-KPX guillemotright Adieresis -40
-KPX guillemotright Aacute -40
-KPX guillemotright AE -46
-KPX guillemotright A -40
-KPX Oslash A -52
-KPX ae y -37
-KPX ae w -35
-KPX ae v -34
-KPX Adieresis y -83
-KPX Adieresis w -79
-KPX Adieresis v -84
-KPX Adieresis u -30
-KPX Adieresis t -27
-KPX Adieresis quoteright -108
-KPX Adieresis quotedblright -76
-KPX Adieresis q -38
-KPX Adieresis o -37
-KPX Adieresis hyphen -30
-KPX Adieresis guilsinglleft -67
-KPX Adieresis guillemotleft -53
-KPX Adieresis g -7
-KPX Adieresis d -28
-KPX Adieresis comma 1
-KPX Adieresis c -35
-KPX Adieresis b -22
-KPX Adieresis a -5
-KPX Adieresis Y -74
-KPX Adieresis W -116
-KPX Adieresis V -130
-KPX Adieresis U -66
-KPX Adieresis T -59
-KPX Adieresis Q -68
-KPX Adieresis O -68
-KPX Adieresis G -68
-KPX Adieresis C -73
-KPX Aacute y -83
-KPX Aacute w -79
-KPX Aacute v -84
-KPX Aacute u -30
-KPX Aacute t -27
-KPX Aacute quoteright -108
-KPX Aacute q -38
-KPX Aacute o -37
-KPX Aacute hyphen -30
-KPX Aacute guilsinglleft -67
-KPX Aacute guillemotleft -53
-KPX Aacute g -7
-KPX Aacute e -32
-KPX Aacute d -28
-KPX Aacute comma 1
-KPX Aacute c -35
-KPX Aacute b -22
-KPX Aacute a -5
-KPX Aacute Y -74
-KPX Aacute W -116
-KPX Aacute V -130
-KPX Aacute U -66
-KPX Aacute T -59
-KPX Aacute Q -68
-KPX Aacute O -68
-KPX Aacute G -68
-KPX Aacute C -73
-KPX Agrave comma 1
-KPX Agrave Y -74
-KPX Agrave W -116
-KPX Agrave V -130
-KPX Agrave U -66
-KPX Agrave T -59
-KPX Agrave Q -68
-KPX Agrave O -68
-KPX Agrave G -68
-KPX Agrave C -73
-KPX Acircumflex comma 1
-KPX Acircumflex Y -74
-KPX Acircumflex W -116
-KPX Acircumflex V -130
-KPX Acircumflex U -66
-KPX Acircumflex T -59
-KPX Acircumflex Q -68
-KPX Acircumflex O -68
-KPX Acircumflex G -68
-KPX Acircumflex C -73
-KPX Atilde comma 1
-KPX Atilde Y -74
-KPX Atilde W -116
-KPX Atilde V -130
-KPX Atilde U -66
-KPX Atilde T -59
-KPX Atilde Q -68
-KPX Atilde O -68
-KPX Atilde G -68
-KPX Atilde C -73
-KPX Aring y -83
-KPX Aring w -79
-KPX Aring v -84
-KPX Aring u -30
-KPX Aring t -27
-KPX Aring quoteright -108
-KPX Aring quotedblright -76
-KPX Aring q -38
-KPX Aring o -37
-KPX Aring hyphen -30
-KPX Aring guilsinglleft -67
-KPX Aring guillemotleft -53
-KPX Aring g -7
-KPX Aring e -32
-KPX Aring d -28
-KPX Aring comma 1
-KPX Aring c -35
-KPX Aring b -22
-KPX Aring a -5
-KPX Aring Y -74
-KPX Aring W -116
-KPX Aring V -130
-KPX Aring U -66
-KPX Aring T -59
-KPX Aring Q -68
-KPX Aring O -68
-KPX Aring G -68
-KPX Aring C -73
-KPX Ccedilla A -33
-KPX Odieresis Y -59
-KPX Odieresis X -51
-KPX Odieresis W -54
-KPX Odieresis V -60
-KPX Odieresis T -9
-KPX Odieresis A -55
-KPX Oacute Y -59
-KPX Oacute W -54
-KPX Oacute V -60
-KPX Oacute T -9
-KPX Oacute A -55
-KPX Ograve Y -59
-KPX Ograve V -60
-KPX Ograve T -9
-KPX Ocircumflex Y -59
-KPX Ocircumflex V -60
-KPX Ocircumflex T -9
-KPX Otilde Y -59
-KPX Otilde V -60
-KPX Otilde T -9
-KPX Udieresis r -29
-KPX Udieresis period -18
-KPX Udieresis p -28
-KPX Udieresis n -25
-KPX Udieresis m -23
-KPX Udieresis comma -17
-KPX Udieresis b 10
-KPX Udieresis A -54
-KPX Uacute r -29
-KPX Uacute period -18
-KPX Uacute p -28
-KPX Uacute n -25
-KPX Uacute m -23
-KPX Uacute comma -17
-KPX Uacute A -54
-KPX Ugrave A -54
-KPX Ucircumflex A -54
-KPX adieresis y -44
-KPX adieresis w -40
-KPX adieresis v -39
-KPX aacute y -44
-KPX aacute w -40
-KPX aacute v -39
-KPX agrave y -44
-KPX agrave w -40
-KPX agrave v -39
-KPX aring y -44
-KPX aring w -40
-KPX aring v -39
-KPX eacute y -31
-KPX eacute w -30
-KPX eacute v -29
-KPX ecircumflex y -31
-KPX ecircumflex w -30
-KPX ecircumflex v -29
-KPX odieresis y -42
-KPX odieresis x -29
-KPX odieresis w -38
-KPX odieresis v -42
-KPX odieresis t -10
-KPX oacute y -42
-KPX oacute w -38
-KPX oacute v -42
-KPX ograve y -42
-KPX ograve w -38
-KPX ograve v -42
-KPX ocircumflex t -10
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-roman-no-9-l/n021004l.pfb b/src/fonts/nimbus-roman-no-9-l/n021004l.pfb
deleted file mode 100644
index b5b6aac..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021004l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-roman-no-9-l/n021004l.pfm b/src/fonts/nimbus-roman-no-9-l/n021004l.pfm
deleted file mode 100644
index bf2093e..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021004l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-roman-no-9-l/n021023l.afm b/src/fonts/nimbus-roman-no-9-l/n021023l.afm
deleted file mode 100644
index 7307603..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021023l.afm
+++ /dev/null
@@ -1,1544 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 13:23:45 2007
-FontName NimbusRomNo9L-ReguItal
-FullName Nimbus Roman No9 L Regular Italic
-FamilyName Nimbus Roman No9 L
-Weight Regular
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle -15.5
-IsFixedPitch false
-UnderlinePosition -100
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -169 -270 1112 924
-CapHeight 653
-XHeight 441
-Ascender 683
-Descender -205
-StartCharMetrics 534
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 39 -11 302 667 ;
-C 34 ; WX 420 ; N quotedbl ; B 144 421 432 666 ;
-C 35 ; WX 500 ; N numbersign ; B 2 0 540 676 ;
-C 36 ; WX 500 ; N dollar ; B 31 -89 497 731 ;
-C 37 ; WX 833 ; N percent ; B 79 -13 790 676 ;
-C 38 ; WX 778 ; N ampersand ; B 76 -18 723 666 ;
-C 39 ; WX 333 ; N quoteright ; B 151 436 290 666 ;
-C 40 ; WX 333 ; N parenleft ; B 42 -181 315 669 ;
-C 41 ; WX 333 ; N parenright ; B 16 -180 289 669 ;
-C 42 ; WX 500 ; N asterisk ; B 128 255 492 666 ;
-C 43 ; WX 675 ; N plus ; B 86 0 590 506 ;
-C 44 ; WX 250 ; N comma ; B -4 -129 135 101 ;
-C 45 ; WX 333 ; N hyphen ; B 49 192 282 255 ;
-C 46 ; WX 250 ; N period ; B 27 -11 138 100 ;
-C 47 ; WX 278 ; N slash ; B -65 -18 386 666 ;
-C 48 ; WX 500 ; N zero ; B 32 -7 497 676 ;
-C 49 ; WX 500 ; N one ; B 49 0 409 676 ;
-C 50 ; WX 500 ; N two ; B 12 0 452 676 ;
-C 51 ; WX 500 ; N three ; B 15 -7 466 676 ;
-C 52 ; WX 500 ; N four ; B 1 0 479 676 ;
-C 53 ; WX 500 ; N five ; B 15 -7 491 666 ;
-C 54 ; WX 500 ; N six ; B 30 -7 521 686 ;
-C 55 ; WX 500 ; N seven ; B 75 -8 537 666 ;
-C 56 ; WX 500 ; N eight ; B 30 -7 493 676 ;
-C 57 ; WX 500 ; N nine ; B 23 -17 492 676 ;
-C 58 ; WX 333 ; N colon ; B 50 -11 261 441 ;
-C 59 ; WX 333 ; N semicolon ; B 27 -129 261 441 ;
-C 60 ; WX 675 ; N less ; B 84 -10 592 516 ;
-C 61 ; WX 675 ; N equal ; B 86 120 590 386 ;
-C 62 ; WX 675 ; N greater ; B 84 -10 592 516 ;
-C 63 ; WX 500 ; N question ; B 132 -12 472 664 ;
-C 64 ; WX 920 ; N at ; B 118 -18 806 666 ;
-C 65 ; WX 611 ; N A ; B -51 0 564 668 ;
-C 66 ; WX 611 ; N B ; B -8 0 588 653 ;
-C 67 ; WX 667 ; N C ; B 66 -18 689 666 ;
-C 68 ; WX 722 ; N D ; B -8 0 700 653 ;
-C 69 ; WX 611 ; N E ; B -1 0 634 653 ;
-C 70 ; WX 611 ; N F ; B 8 0 645 653 ;
-C 71 ; WX 722 ; N G ; B 52 -18 722 666 ;
-C 72 ; WX 722 ; N H ; B -8 0 767 653 ;
-C 73 ; WX 333 ; N I ; B -8 0 384 653 ; L J IJ ;
-C 74 ; WX 444 ; N J ; B -6 -18 491 653 ;
-C 75 ; WX 667 ; N K ; B 7 0 722 653 ;
-C 76 ; WX 556 ; N L ; B -8 0 559 653 ; L periodcentered Ldot ;
-C 77 ; WX 833 ; N M ; B -18 0 873 653 ;
-C 78 ; WX 667 ; N N ; B -20 -15 727 653 ; L o afii61352 ;
-C 79 ; WX 722 ; N O ; B 60 -18 700 666 ;
-C 80 ; WX 611 ; N P ; B 0 0 605 653 ;
-C 81 ; WX 722 ; N Q ; B 59 -183 699 666 ;
-C 82 ; WX 611 ; N R ; B -13 0 588 653 ;
-C 83 ; WX 500 ; N S ; B 17 -18 508 667 ;
-C 84 ; WX 556 ; N T ; B 59 0 633 653 ; L M trademark ;
-C 85 ; WX 722 ; N U ; B 102 -18 765 653 ;
-C 86 ; WX 611 ; N V ; B 76 -18 688 653 ;
-C 87 ; WX 833 ; N W ; B 71 -18 906 653 ;
-C 88 ; WX 611 ; N X ; B -29 0 655 653 ;
-C 89 ; WX 556 ; N Y ; B 78 0 633 653 ;
-C 90 ; WX 556 ; N Z ; B -6 0 606 653 ;
-C 91 ; WX 389 ; N bracketleft ; B 21 -153 391 663 ;
-C 92 ; WX 278 ; N backslash ; B -41 -18 319 666 ;
-C 93 ; WX 389 ; N bracketright ; B 12 -153 382 663 ;
-C 94 ; WX 422 ; N asciicircum ; B 0 301 422 666 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 171 436 310 666 ;
-C 97 ; WX 500 ; N a ; B 17 -11 476 441 ;
-C 98 ; WX 500 ; N b ; B 23 -11 473 683 ;
-C 99 ; WX 444 ; N c ; B 30 -11 425 441 ;
-C 100 ; WX 500 ; N d ; B 15 -13 527 683 ;
-C 101 ; WX 444 ; N e ; B 31 -11 412 441 ;
-C 102 ; WX 278 ; N f ; B -147 -207 424 678 ; L l fl ; L i fi ;
-C 103 ; WX 500 ; N g ; B 8 -206 472 441 ;
-C 104 ; WX 500 ; N h ; B 19 -9 478 683 ;
-C 105 ; WX 278 ; N i ; B 49 -11 264 654 ; L j ij ;
-C 106 ; WX 278 ; N j ; B -124 -207 276 654 ;
-C 107 ; WX 444 ; N k ; B 14 -11 461 683 ;
-C 108 ; WX 278 ; N l ; B 40 -11 279 683 ; L periodcentered ldot ;
-C 109 ; WX 722 ; N m ; B 12 -9 704 441 ;
-C 110 ; WX 500 ; N n ; B 14 -9 474 441 ;
-C 111 ; WX 500 ; N o ; B 27 -11 468 441 ;
-C 112 ; WX 500 ; N p ; B -75 -205 469 442 ;
-C 113 ; WX 500 ; N q ; B 25 -209 483 441 ;
-C 114 ; WX 389 ; N r ; B 45 0 412 441 ;
-C 115 ; WX 389 ; N s ; B 16 -13 366 442 ;
-C 116 ; WX 278 ; N t ; B 37 -11 296 546 ;
-C 117 ; WX 500 ; N u ; B 42 -11 475 441 ;
-C 118 ; WX 444 ; N v ; B 21 -18 426 441 ;
-C 119 ; WX 667 ; N w ; B 16 -18 648 441 ;
-C 120 ; WX 444 ; N x ; B -27 -11 447 441 ;
-C 121 ; WX 444 ; N y ; B -24 -206 426 441 ;
-C 122 ; WX 389 ; N z ; B -2 -81 380 428 ;
-C 123 ; WX 400 ; N braceleft ; B 51 -177 407 687 ;
-C 124 ; WX 275 ; N bar ; B 105 -18 171 666 ;
-C 125 ; WX 400 ; N braceright ; B -7 -177 349 687 ;
-C 126 ; WX 541 ; N asciitilde ; B 40 186 502 320 ;
-C 161 ; WX 389 ; N exclamdown ; B 59 -205 321 474 ;
-C 162 ; WX 500 ; N cent ; B 77 -143 472 560 ;
-C 163 ; WX 500 ; N sterling ; B 10 -6 517 670 ;
-C 164 ; WX 167 ; N fraction ; B -169 -10 337 676 ;
-C 165 ; WX 500 ; N yen ; B 27 0 603 653 ;
-C 166 ; WX 500 ; N florin ; B 25 -182 507 682 ;
-C 167 ; WX 500 ; N section ; B 53 -162 461 666 ;
-C 168 ; WX 500 ; N currency ; B -22 53 522 597 ;
-C 169 ; WX 214 ; N quotesingle ; B 132 421 241 666 ;
-C 170 ; WX 556 ; N quotedblleft ; B 166 436 514 666 ;
-C 171 ; WX 500 ; N guillemotleft ; B 53 37 445 403 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 51 37 281 403 ;
-C 173 ; WX 333 ; N guilsinglright ; B 52 37 282 403 ;
-C 174 ; WX 500 ; N fi ; B -141 -207 481 681 ;
-C 175 ; WX 500 ; N fl ; B -141 -204 518 682 ;
-C 177 ; WX 500 ; N endash ; B -6 197 505 243 ;
-C 178 ; WX 500 ; N dagger ; B 101 -159 488 666 ;
-C 179 ; WX 500 ; N daggerdbl ; B 22 -143 491 666 ;
-C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ;
-C 182 ; WX 523 ; N paragraph ; B 55 -123 616 653 ;
-C 183 ; WX 350 ; N bullet ; B 40 191 310 461 ;
-C 184 ; WX 333 ; N quotesinglbase ; B 44 -129 183 101 ;
-C 185 ; WX 556 ; N quotedblbase ; B 57 -129 405 101 ;
-C 186 ; WX 556 ; N quotedblright ; B 151 436 499 666 ;
-C 187 ; WX 500 ; N guillemotright ; B 55 37 447 403 ;
-C 188 ; WX 889 ; N ellipsis ; B 57 -11 762 100 ;
-C 189 ; WX 1000 ; N perthousand ; B 25 -19 1010 706 ;
-C 191 ; WX 500 ; N questiondown ; B 28 -205 367 473 ;
-C 193 ; WX 333 ; N grave ; B 121 492 311 664 ;
-C 194 ; WX 333 ; N acute ; B 180 494 403 664 ;
-C 195 ; WX 333 ; N circumflex ; B 91 492 385 661 ;
-C 196 ; WX 333 ; N tilde ; B 100 517 427 624 ;
-C 197 ; WX 333 ; N macron ; B 99 532 411 583 ;
-C 198 ; WX 333 ; N breve ; B 117 492 418 650 ;
-C 199 ; WX 333 ; N dotaccent ; B 207 508 305 606 ;
-C 200 ; WX 333 ; N dieresis ; B 107 508 405 606 ;
-C 202 ; WX 333 ; N ring ; B 155 508 355 707 ;
-C 203 ; WX 333 ; N cedilla ; B -30 -217 182 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 93 494 486 664 ;
-C 206 ; WX 333 ; N ogonek ; B -20 -169 200 40 ;
-C 207 ; WX 333 ; N caron ; B 121 492 426 661 ;
-C 208 ; WX 889 ; N emdash ; B -6 197 894 243 ;
-C 225 ; WX 889 ; N AE ; B -27 0 911 653 ;
-C 227 ; WX 276 ; N ordfeminine ; B 42 406 352 676 ;
-C 232 ; WX 556 ; N Lslash ; B -8 0 559 653 ;
-C 233 ; WX 722 ; N Oslash ; B 60 -105 699 722 ;
-C 234 ; WX 944 ; N OE ; B 49 -8 964 666 ;
-C 235 ; WX 310 ; N ordmasculine ; B 67 406 362 676 ;
-C 241 ; WX 667 ; N ae ; B 23 -11 640 441 ;
-C 245 ; WX 278 ; N dotlessi ; B 49 -11 235 441 ;
-C 248 ; WX 278 ; N lslash ; B 37 -11 307 683 ;
-C 249 ; WX 500 ; N oslash ; B 28 -135 469 554 ;
-C 250 ; WX 667 ; N oe ; B 20 -12 646 441 ;
-C 251 ; WX 500 ; N germandbls ; B -168 -207 493 679 ;
-C -1 ; WX 611 ; N Adieresis ; B -51 0 564 818 ;
-C -1 ; WX 611 ; N Aacute ; B -51 0 564 876 ;
-C -1 ; WX 611 ; N Agrave ; B -51 0 564 876 ;
-C -1 ; WX 611 ; N Acircumflex ; B -51 0 564 873 ;
-C -1 ; WX 611 ; N Abreve ; B -51 0 564 862 ;
-C -1 ; WX 611 ; N Atilde ; B -51 0 566 836 ;
-C -1 ; WX 611 ; N Aring ; B -51 0 564 904 ;
-C -1 ; WX 611 ; N Aogonek ; B -51 -169 707 668 ;
-C -1 ; WX 667 ; N Ccedilla ; B 66 -217 689 666 ;
-C -1 ; WX 667 ; N Cacute ; B 66 -18 689 876 ;
-C -1 ; WX 667 ; N Ccaron ; B 66 -18 689 873 ;
-C -1 ; WX 722 ; N Dcaron ; B -8 0 700 873 ;
-C -1 ; WX 611 ; N Edieresis ; B -1 0 634 818 ;
-C -1 ; WX 611 ; N Eacute ; B -1 0 634 876 ;
-C -1 ; WX 611 ; N Egrave ; B -1 0 634 876 ;
-C -1 ; WX 611 ; N Ecircumflex ; B -1 0 634 873 ;
-C -1 ; WX 611 ; N Ecaron ; B -1 0 634 873 ;
-C -1 ; WX 611 ; N Edotaccent ; B -1 0 634 818 ;
-C -1 ; WX 611 ; N Eogonek ; B -1 -169 651 653 ;
-C -1 ; WX 722 ; N Gbreve ; B 52 -18 722 862 ;
-C -1 ; WX 333 ; N Idieresis ; B -8 0 435 818 ;
-C -1 ; WX 333 ; N Iacute ; B -8 0 403 876 ;
-C -1 ; WX 333 ; N Igrave ; B -8 0 384 876 ;
-C -1 ; WX 333 ; N Icircumflex ; B -8 0 425 873 ;
-C -1 ; WX 333 ; N Idotaccent ; B -8 0 384 818 ;
-C -1 ; WX 556 ; N Lacute ; B -8 0 559 876 ;
-C -1 ; WX 556 ; N Lcaron ; B -8 0 596 666 ;
-C -1 ; WX 667 ; N Nacute ; B -20 -15 727 876 ;
-C -1 ; WX 667 ; N Ncaron ; B -20 -15 727 873 ;
-C -1 ; WX 667 ; N Ntilde ; B -20 -15 727 836 ;
-C -1 ; WX 722 ; N Odieresis ; B 60 -18 700 818 ;
-C -1 ; WX 722 ; N Oacute ; B 60 -18 700 876 ;
-C -1 ; WX 722 ; N Ograve ; B 60 -18 700 876 ;
-C -1 ; WX 722 ; N Ocircumflex ; B 60 -18 700 873 ;
-C -1 ; WX 722 ; N Otilde ; B 60 -18 700 836 ;
-C -1 ; WX 722 ; N Ohungarumlaut ; B 60 -18 700 876 ;
-C -1 ; WX 611 ; N Racute ; B -13 0 588 876 ;
-C -1 ; WX 611 ; N Rcaron ; B -13 0 588 873 ;
-C -1 ; WX 500 ; N Sacute ; B 17 -18 508 876 ;
-C -1 ; WX 500 ; N Scaron ; B 17 -18 520 873 ;
-C -1 ; WX 500 ; N Scedilla ; B 17 -217 508 667 ;
-C -1 ; WX 556 ; N Tcaron ; B 59 0 633 873 ;
-C -1 ; WX 722 ; N Udieresis ; B 102 -18 765 818 ;
-C -1 ; WX 722 ; N Uacute ; B 102 -18 765 876 ;
-C -1 ; WX 722 ; N Ugrave ; B 102 -18 765 876 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 102 -18 765 873 ;
-C -1 ; WX 722 ; N Uring ; B 102 -18 765 919 ;
-C -1 ; WX 722 ; N Uhungarumlaut ; B 102 -18 765 876 ;
-C -1 ; WX 556 ; N Yacute ; B 78 0 633 876 ;
-C -1 ; WX 556 ; N Zacute ; B -6 0 606 876 ;
-C -1 ; WX 556 ; N Zcaron ; B -6 0 606 873 ;
-C -1 ; WX 556 ; N Zdotaccent ; B -6 0 606 818 ;
-C -1 ; WX 611 ; N Amacron ; B -51 0 564 795 ;
-C -1 ; WX 556 ; N Tcommaaccent ; B 59 -270 633 653 ;
-C -1 ; WX 556 ; N Ydieresis ; B 78 0 633 818 ;
-C -1 ; WX 611 ; N Emacron ; B -1 0 634 795 ;
-C -1 ; WX 333 ; N Imacron ; B -8 0 441 795 ;
-C -1 ; WX 333 ; N Iogonek ; B -8 -169 384 653 ;
-C -1 ; WX 667 ; N Kcommaaccent ; B 7 -270 722 653 ;
-C -1 ; WX 556 ; N Lcommaaccent ; B -8 -270 559 653 ;
-C -1 ; WX 667 ; N Ncommaaccent ; B -20 -270 727 653 ;
-C -1 ; WX 722 ; N Omacron ; B 60 -18 700 795 ;
-C -1 ; WX 611 ; N Rcommaaccent ; B -13 -270 588 653 ;
-C -1 ; WX 722 ; N Gcommaaccent ; B 52 -270 722 666 ;
-C -1 ; WX 722 ; N Umacron ; B 102 -18 765 795 ;
-C -1 ; WX 722 ; N Uogonek ; B 102 -169 765 653 ;
-C -1 ; WX 500 ; N adieresis ; B 17 -11 489 606 ;
-C -1 ; WX 500 ; N aacute ; B 17 -11 487 664 ;
-C -1 ; WX 500 ; N agrave ; B 17 -11 476 664 ;
-C -1 ; WX 500 ; N acircumflex ; B 17 -11 476 661 ;
-C -1 ; WX 500 ; N abreve ; B 17 -11 502 650 ;
-C -1 ; WX 500 ; N atilde ; B 17 -11 511 624 ;
-C -1 ; WX 500 ; N aring ; B 17 -11 476 707 ;
-C -1 ; WX 500 ; N aogonek ; B 17 -169 500 441 ;
-C -1 ; WX 444 ; N cacute ; B 30 -11 458 664 ;
-C -1 ; WX 444 ; N ccaron ; B 30 -11 484 661 ;
-C -1 ; WX 444 ; N ccedilla ; B 26 -217 425 441 ;
-C -1 ; WX 521 ; N dcaron ; B 15 -13 641 683 ;
-C -1 ; WX 444 ; N edieresis ; B 31 -11 451 606 ;
-C -1 ; WX 444 ; N eacute ; B 31 -11 459 664 ;
-C -1 ; WX 444 ; N egrave ; B 31 -11 412 664 ;
-C -1 ; WX 444 ; N ecircumflex ; B 31 -11 441 661 ;
-C -1 ; WX 444 ; N ecaron ; B 31 -11 482 661 ;
-C -1 ; WX 444 ; N edotaccent ; B 31 -11 412 606 ;
-C -1 ; WX 444 ; N eogonek ; B 31 -169 444 441 ;
-C -1 ; WX 500 ; N gbreve ; B 8 -206 502 650 ;
-C -1 ; WX 278 ; N idieresis ; B 49 -11 353 606 ;
-C -1 ; WX 278 ; N iacute ; B 49 -11 356 664 ;
-C -1 ; WX 278 ; N igrave ; B 49 -11 284 664 ;
-C -1 ; WX 278 ; N icircumflex ; B 34 -11 328 661 ;
-C -1 ; WX 278 ; N lacute ; B 40 -11 376 876 ;
-C -1 ; WX 278 ; N lcaron ; B 40 -11 395 683 ;
-C -1 ; WX 500 ; N nacute ; B 14 -9 487 664 ;
-C -1 ; WX 500 ; N ncaron ; B 14 -9 510 661 ;
-C -1 ; WX 500 ; N ntilde ; B 14 -9 476 624 ;
-C -1 ; WX 500 ; N odieresis ; B 27 -11 489 606 ;
-C -1 ; WX 500 ; N oacute ; B 27 -11 487 664 ;
-C -1 ; WX 500 ; N ograve ; B 27 -11 468 664 ;
-C -1 ; WX 500 ; N ocircumflex ; B 27 -11 468 661 ;
-C -1 ; WX 500 ; N otilde ; B 27 -11 496 624 ;
-C -1 ; WX 500 ; N ohungarumlaut ; B 27 -11 570 664 ;
-C -1 ; WX 389 ; N racute ; B 45 0 431 664 ;
-C -1 ; WX 389 ; N sacute ; B 16 -13 431 664 ;
-C -1 ; WX 389 ; N scaron ; B 16 -13 454 661 ;
-C -1 ; WX 389 ; N scommaaccent ; B 16 -270 366 442 ;
-C -1 ; WX 278 ; N tcaron ; B 37 -11 378 666 ;
-C -1 ; WX 500 ; N udieresis ; B 42 -11 479 606 ;
-C -1 ; WX 500 ; N uacute ; B 42 -11 477 664 ;
-C -1 ; WX 500 ; N ugrave ; B 42 -11 475 664 ;
-C -1 ; WX 500 ; N ucircumflex ; B 42 -11 475 661 ;
-C -1 ; WX 500 ; N uring ; B 42 -11 475 707 ;
-C -1 ; WX 500 ; N uhungarumlaut ; B 42 -11 570 664 ;
-C -1 ; WX 444 ; N yacute ; B -24 -206 459 664 ;
-C -1 ; WX 389 ; N zacute ; B -2 -81 431 664 ;
-C -1 ; WX 389 ; N zcaron ; B -2 -81 434 661 ;
-C -1 ; WX 389 ; N zdotaccent ; B -2 -81 380 606 ;
-C -1 ; WX 444 ; N ydieresis ; B -24 -206 441 606 ;
-C -1 ; WX 278 ; N tcommaaccent ; B -21 -270 296 546 ;
-C -1 ; WX 500 ; N amacron ; B 17 -11 495 583 ;
-C -1 ; WX 444 ; N emacron ; B 31 -11 467 583 ;
-C -1 ; WX 278 ; N imacron ; B 49 -11 384 583 ;
-C -1 ; WX 444 ; N kcommaaccent ; B 14 -270 461 683 ;
-C -1 ; WX 278 ; N lcommaaccent ; B -21 -270 279 683 ;
-C -1 ; WX 500 ; N ncommaaccent ; B 14 -270 474 441 ;
-C -1 ; WX 500 ; N omacron ; B 27 -11 495 583 ;
-C -1 ; WX 389 ; N rcommaaccent ; B 35 -270 412 441 ;
-C -1 ; WX 500 ; N umacron ; B 42 -11 495 583 ;
-C -1 ; WX 500 ; N uogonek ; B 42 -169 500 441 ;
-C -1 ; WX 389 ; N rcaron ; B 45 0 454 661 ;
-C -1 ; WX 389 ; N scedilla ; B -2 -217 366 442 ;
-C -1 ; WX 500 ; N gcommaaccent ; B 8 -206 472 706 ;
-C -1 ; WX 278 ; N iogonek ; B 49 -169 278 654 ;
-C -1 ; WX 500 ; N Scommaaccent ; B 17 -270 508 667 ;
-C -1 ; WX 722 ; N Eth ; B -8 0 700 653 ;
-C -1 ; WX 722 ; N Dcroat ; B -8 0 700 653 ;
-C -1 ; WX 611 ; N Thorn ; B 0 0 569 653 ;
-C -1 ; WX 500 ; N dcroat ; B 15 -13 558 683 ;
-C -1 ; WX 500 ; N eth ; B 27 -11 482 683 ;
-C -1 ; WX 500 ; N thorn ; B -75 -205 469 683 ;
-C -1 ; WX 500 ; N Euro ; B 57 0 668 693 ;
-C -1 ; WX 300 ; N onesuperior ; B 43 271 284 676 ;
-C -1 ; WX 300 ; N twosuperior ; B 33 271 324 676 ;
-C -1 ; WX 300 ; N threesuperior ; B 43 268 339 676 ;
-C -1 ; WX 400 ; N degree ; B 101 390 387 676 ;
-C -1 ; WX 675 ; N minus ; B 86 220 590 286 ;
-C -1 ; WX 675 ; N multiply ; B 93 8 582 497 ;
-C -1 ; WX 675 ; N divide ; B 86 -11 590 517 ;
-C -1 ; WX 980 ; N trademark ; B 30 247 957 653 ;
-C -1 ; WX 675 ; N plusminus ; B 86 0 590 568 ;
-C -1 ; WX 750 ; N onehalf ; B 34 -10 749 676 ;
-C -1 ; WX 750 ; N onequarter ; B 33 -10 736 676 ;
-C -1 ; WX 750 ; N threequarters ; B 23 -10 736 676 ;
-C -1 ; WX 333 ; N commaaccent ; B 7 -270 146 -40 ;
-C -1 ; WX 760 ; N copyright ; B 41 -18 719 666 ;
-C -1 ; WX 760 ; N registered ; B 41 -18 719 666 ;
-C -1 ; WX 494 ; N lozenge ; B 18 0 466 740 ;
-C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
-C -1 ; WX 564 ; N notequal ; B 30 -3 534 509 ;
-C -1 ; WX 549 ; N radical ; B -2 -65 526 924 ;
-C -1 ; WX 675 ; N lessequal ; B 84 0 592 628 ;
-C -1 ; WX 675 ; N greaterequal ; B 84 0 592 628 ;
-C -1 ; WX 675 ; N logicalnot ; B 86 108 590 386 ;
-C -1 ; WX 713 ; N summation ; B 14 -123 695 752 ;
-C -1 ; WX 494 ; N partialdiff ; B 26 -10 462 753 ;
-C -1 ; WX 275 ; N brokenbar ; B 105 -18 171 666 ;
-C -1 ; WX 500 ; N mu ; B -30 -209 497 428 ;
-C -1 ; WX 611 ; N afii10017 ; B -51 0 564 668 ;
-C -1 ; WX 682 ; N afii10018 ; B -8 0 714 653 ;
-C -1 ; WX 611 ; N afii10019 ; B -8 0 588 653 ;
-C -1 ; WX 640 ; N afii10020 ; B -8 0 672 662 ;
-C -1 ; WX 747 ; N afii10021 ; B -40 -129 785 653 ;
-C -1 ; WX 611 ; N afii10022 ; B -8 0 627 653 ;
-C -1 ; WX 611 ; N afii10023 ; B -8 0 627 801 ;
-C -1 ; WX 1073 ; N afii10024 ; B -29 0 1112 668 ;
-C -1 ; WX 575 ; N afii10025 ; B -30 -14 541 676 ;
-C -1 ; WX 814 ; N afii10026 ; B -8 0 852 653 ;
-C -1 ; WX 814 ; N afii10027 ; B -8 0 852 861 ;
-C -1 ; WX 729 ; N afii10028 ; B -8 0 783 668 ;
-C -1 ; WX 755 ; N afii10029 ; B -50 -13 793 653 ;
-C -1 ; WX 828 ; N afii10030 ; B -18 0 873 653 ;
-C -1 ; WX 722 ; N afii10031 ; B -8 0 767 653 ;
-C -1 ; WX 722 ; N afii10032 ; B 60 -18 700 666 ;
-C -1 ; WX 805 ; N afii10033 ; B -8 0 850 653 ;
-C -1 ; WX 611 ; N afii10034 ; B -8 0 597 653 ;
-C -1 ; WX 667 ; N afii10035 ; B 66 -18 689 666 ;
-C -1 ; WX 556 ; N afii10036 ; B 59 0 633 653 ;
-C -1 ; WX 730 ; N afii10037 ; B -23 -12 765 653 ;
-C -1 ; WX 801 ; N afii10038 ; B 48 0 783 653 ;
-C -1 ; WX 611 ; N afii10039 ; B -29 0 655 653 ;
-C -1 ; WX 807 ; N afii10040 ; B -8 -129 851 653 ;
-C -1 ; WX 772 ; N afii10041 ; B 133 0 816 653 ;
-C -1 ; WX 1063 ; N afii10042 ; B -8 0 1108 653 ;
-C -1 ; WX 1065 ; N afii10043 ; B -8 -129 1109 653 ;
-C -1 ; WX 731 ; N afii10044 ; B 59 0 662 653 ;
-C -1 ; WX 961 ; N afii10045 ; B -8 0 1006 653 ;
-C -1 ; WX 645 ; N afii10046 ; B -8 0 576 653 ;
-C -1 ; WX 671 ; N afii10047 ; B -32 -14 649 676 ;
-C -1 ; WX 1191 ; N afii10048 ; B -8 -14 1080 676 ;
-C -1 ; WX 746 ; N afii10049 ; B -28 0 791 653 ;
-C -1 ; WX 500 ; N afii10065 ; B 17 -11 476 441 ;
-C -1 ; WX 500 ; N afii10066 ; B 30 -10 590 689 ;
-C -1 ; WX 429 ; N afii10067 ; B 31 -11 397 450 ;
-C -1 ; WX 354 ; N afii10068 ; B 18 -11 334 441 ;
-C -1 ; WX 552 ; N afii10069 ; B 27 -11 531 675 ;
-C -1 ; WX 444 ; N afii10070 ; B 31 -11 412 441 ;
-C -1 ; WX 444 ; N afii10071 ; B 31 -11 469 589 ;
-C -1 ; WX 1058 ; N afii10072 ; B 13 -11 1039 441 ;
-C -1 ; WX 391 ; N afii10073 ; B 5 -10 375 459 ;
-C -1 ; WX 500 ; N afii10074 ; B 42 -11 475 441 ;
-C -1 ; WX 500 ; N afii10075 ; B 42 -11 525 649 ;
-C -1 ; WX 491 ; N afii10076 ; B 14 0 503 460 ;
-C -1 ; WX 538 ; N afii10077 ; B 5 -9 513 432 ;
-C -1 ; WX 731 ; N afii10078 ; B 5 -18 706 432 ;
-C -1 ; WX 500 ; N afii10079 ; B 14 -9 474 441 ;
-C -1 ; WX 500 ; N afii10080 ; B 27 -11 468 441 ;
-C -1 ; WX 500 ; N afii10081 ; B 14 -9 474 441 ;
-C -1 ; WX 500 ; N afii10082 ; B -75 -205 469 442 ;
-C -1 ; WX 444 ; N afii10083 ; B 30 -11 425 441 ;
-C -1 ; WX 722 ; N afii10084 ; B 12 -9 704 441 ;
-C -1 ; WX 444 ; N afii10085 ; B -24 -206 426 441 ;
-C -1 ; WX 771 ; N afii10086 ; B 25 -205 740 678 ;
-C -1 ; WX 444 ; N afii10087 ; B -27 -11 447 441 ;
-C -1 ; WX 500 ; N afii10088 ; B 42 -119 475 441 ;
-C -1 ; WX 500 ; N afii10089 ; B 58 -9 475 441 ;
-C -1 ; WX 750 ; N afii10090 ; B 42 -11 725 441 ;
-C -1 ; WX 750 ; N afii10091 ; B 42 -119 725 441 ;
-C -1 ; WX 492 ; N afii10092 ; B 42 -11 475 452 ;
-C -1 ; WX 684 ; N afii10093 ; B 42 -12 659 441 ;
-C -1 ; WX 420 ; N afii10094 ; B 42 -12 403 441 ;
-C -1 ; WX 457 ; N afii10095 ; B 30 -11 425 441 ;
-C -1 ; WX 700 ; N afii10096 ; B 14 -11 668 441 ;
-C -1 ; WX 560 ; N afii10097 ; B 17 -9 512 432 ;
-C -1 ; WX 611 ; N uni0400 ; B -8 0 627 875 ;
-C -1 ; WX 669 ; N afii10051 ; B 59 -146 692 653 ;
-C -1 ; WX 556 ; N afii10052 ; B -8 0 672 873 ;
-C -1 ; WX 667 ; N afii10053 ; B 10 -14 707 676 ;
-C -1 ; WX 500 ; N afii10054 ; B 17 -18 508 667 ;
-C -1 ; WX 333 ; N afii10055 ; B -8 0 384 653 ;
-C -1 ; WX 333 ; N afii10056 ; B -8 0 435 818 ;
-C -1 ; WX 444 ; N afii10057 ; B -6 -18 491 653 ;
-C -1 ; WX 896 ; N afii10058 ; B -48 -13 922 653 ;
-C -1 ; WX 922 ; N afii10059 ; B -8 0 938 653 ;
-C -1 ; WX 758 ; N afii10060 ; B 59 0 742 653 ;
-C -1 ; WX 743 ; N afii10061 ; B 7 0 798 873 ;
-C -1 ; WX 814 ; N uni040D ; B -8 0 852 875 ;
-C -1 ; WX 730 ; N afii10062 ; B -23 -12 765 861 ;
-C -1 ; WX 814 ; N afii10145 ; B -7 -129 851 653 ;
-C -1 ; WX 444 ; N uni0450 ; B 31 -11 420 663 ;
-C -1 ; WX 500 ; N afii10099 ; B 19 -203 427 683 ;
-C -1 ; WX 454 ; N afii10100 ; B 17 0 490 661 ;
-C -1 ; WX 444 ; N afii10101 ; B 10 -10 438 460 ;
-C -1 ; WX 389 ; N afii10102 ; B 16 -13 366 442 ;
-C -1 ; WX 278 ; N afii10103 ; B 49 -11 264 654 ;
-C -1 ; WX 278 ; N afii10104 ; B 49 -11 377 589 ;
-C -1 ; WX 278 ; N afii10105 ; B -124 -207 276 654 ;
-C -1 ; WX 694 ; N afii10106 ; B 5 -11 700 432 ;
-C -1 ; WX 646 ; N afii10107 ; B 14 -11 661 441 ;
-C -1 ; WX 500 ; N afii10108 ; B 19 -9 478 683 ;
-C -1 ; WX 491 ; N afii10109 ; B 14 0 503 680 ;
-C -1 ; WX 500 ; N uni045D ; B 42 -11 475 664 ;
-C -1 ; WX 444 ; N afii10110 ; B -24 -206 440 649 ;
-C -1 ; WX 500 ; N afii10193 ; B 42 -119 475 441 ;
-C -1 ; WX 645 ; N uni048C ; B -8 0 576 653 ;
-C -1 ; WX 420 ; N uni048D ; B 25 -12 403 441 ;
-C -1 ; WX 611 ; N uni048E ; B -8 0 597 653 ;
-C -1 ; WX 500 ; N uni048F ; B -75 -205 469 442 ;
-C -1 ; WX 556 ; N afii10050 ; B -94 0 652 767 ;
-C -1 ; WX 418 ; N afii10098 ; B -57 0 460 538 ;
-C -1 ; WX 556 ; N uni0492 ; B -8 0 672 662 ;
-C -1 ; WX 354 ; N uni0493 ; B 18 -11 334 441 ;
-C -1 ; WX 598 ; N uni0494 ; B -8 -242 672 662 ;
-C -1 ; WX 1073 ; N uni0496 ; B -29 -129 1112 668 ;
-C -1 ; WX 1058 ; N uni0497 ; B 13 -119 1039 441 ;
-C -1 ; WX 575 ; N uni0498 ; B -30 -165 541 676 ;
-C -1 ; WX 391 ; N uni0499 ; B -2 -165 375 459 ;
-C -1 ; WX 743 ; N uni049A ; B 7 -129 798 668 ;
-C -1 ; WX 491 ; N uni049B ; B 14 -119 503 460 ;
-C -1 ; WX 743 ; N uni049E ; B 7 0 798 668 ;
-C -1 ; WX 491 ; N uni049F ; B 14 0 503 460 ;
-C -1 ; WX 722 ; N uni04A2 ; B -8 -129 767 653 ;
-C -1 ; WX 500 ; N uni04A3 ; B 14 -119 474 441 ;
-C -1 ; WX 1000 ; N uni04A6 ; B -7 -242 1009 653 ;
-C -1 ; WX 667 ; N uni04AA ; B 66 -165 689 666 ;
-C -1 ; WX 444 ; N uni04AB ; B 30 -165 425 441 ;
-C -1 ; WX 556 ; N uni04AC ; B 59 -129 633 653 ;
-C -1 ; WX 484 ; N uni04AD ; B 59 -119 513 450 ;
-C -1 ; WX 556 ; N uni04AE ; B 78 0 633 653 ;
-C -1 ; WX 556 ; N uni04AF ; B 66 -214 514 324 ;
-C -1 ; WX 556 ; N uni04B0 ; B 78 0 633 653 ;
-C -1 ; WX 556 ; N uni04B1 ; B 96 -106 544 432 ;
-C -1 ; WX 611 ; N uni04B2 ; B -29 -129 655 653 ;
-C -1 ; WX 444 ; N uni04B3 ; B -27 -119 447 441 ;
-C -1 ; WX 772 ; N uni04B6 ; B 133 -129 816 653 ;
-C -1 ; WX 500 ; N uni04B7 ; B 58 -119 475 441 ;
-C -1 ; WX 722 ; N uni04BA ; B 23 0 706 653 ;
-C -1 ; WX 500 ; N uni04BB ; B 19 -9 478 683 ;
-C -1 ; WX 333 ; N uni04C0 ; B -8 0 384 653 ;
-C -1 ; WX 1073 ; N uni04C1 ; B -29 0 1112 861 ;
-C -1 ; WX 1058 ; N uni04C2 ; B 13 -11 1039 649 ;
-C -1 ; WX 611 ; N uni04D0 ; B -51 0 564 862 ;
-C -1 ; WX 500 ; N uni04D1 ; B 17 -11 502 650 ;
-C -1 ; WX 611 ; N uni04D2 ; B -51 0 564 818 ;
-C -1 ; WX 500 ; N uni04D3 ; B 17 -11 489 606 ;
-C -1 ; WX 889 ; N uni04D4 ; B -27 0 911 653 ;
-C -1 ; WX 667 ; N uni04D5 ; B 23 -11 640 441 ;
-C -1 ; WX 611 ; N uni04D6 ; B -8 0 627 861 ;
-C -1 ; WX 444 ; N uni04D7 ; B 31 -11 500 649 ;
-C -1 ; WX 444 ; N uni04D8 ; B 31 -12 678 675 ;
-C -1 ; WX 444 ; N afii10846 ; B 31 -11 412 441 ;
-C -1 ; WX 444 ; N uni04DA ; B 31 -12 678 793 ;
-C -1 ; WX 444 ; N uni04DB ; B 30 -11 469 589 ;
-C -1 ; WX 1073 ; N uni04DC ; B -29 0 1112 801 ;
-C -1 ; WX 1058 ; N uni04DD ; B 13 -11 1039 589 ;
-C -1 ; WX 575 ; N uni04DE ; B -30 -14 541 794 ;
-C -1 ; WX 391 ; N uni04DF ; B 5 -10 429 577 ;
-C -1 ; WX 814 ; N uni04E2 ; B -8 0 852 754 ;
-C -1 ; WX 500 ; N uni04E3 ; B 42 -11 494 542 ;
-C -1 ; WX 814 ; N uni04E4 ; B -8 0 852 801 ;
-C -1 ; WX 500 ; N uni04E5 ; B 42 -11 493 589 ;
-C -1 ; WX 722 ; N uni04E6 ; B 60 -18 700 818 ;
-C -1 ; WX 500 ; N uni04E7 ; B 27 -11 489 606 ;
-C -1 ; WX 722 ; N uni04E8 ; B 60 -18 700 666 ;
-C -1 ; WX 500 ; N uni04E9 ; B 27 -11 468 441 ;
-C -1 ; WX 722 ; N uni04EA ; B 60 -18 700 801 ;
-C -1 ; WX 500 ; N uni04EB ; B 27 -11 487 589 ;
-C -1 ; WX 671 ; N uni04EC ; B -32 -14 649 831 ;
-C -1 ; WX 457 ; N uni04ED ; B 30 -11 470 589 ;
-C -1 ; WX 730 ; N uni04EE ; B -23 -12 765 754 ;
-C -1 ; WX 444 ; N uni04EF ; B -24 -206 426 542 ;
-C -1 ; WX 730 ; N uni04F0 ; B -23 -12 765 801 ;
-C -1 ; WX 444 ; N uni04F1 ; B -24 -206 426 589 ;
-C -1 ; WX 730 ; N uni04F2 ; B -23 -12 765 873 ;
-C -1 ; WX 444 ; N uni04F3 ; B -24 -206 461 661 ;
-C -1 ; WX 772 ; N uni04F4 ; B 133 0 816 801 ;
-C -1 ; WX 500 ; N uni04F5 ; B 58 -9 493 589 ;
-C -1 ; WX 1021 ; N uni04F8 ; B -8 0 1066 801 ;
-C -1 ; WX 684 ; N uni04F9 ; B 42 -12 659 589 ;
-C -1 ; WX 354 ; N uniF6C4 ; B 18 -11 349 533 ;
-C -1 ; WX 500 ; N uniF6C5 ; B 28 -10 590 689 ;
-C -1 ; WX 500 ; N uniF6C6 ; B -19 -231 483 441 ;
-C -1 ; WX 500 ; N uniF6C7 ; B 42 -11 475 533 ;
-C -1 ; WX 750 ; N uniF6C8 ; B 42 -11 740 533 ;
-C -1 ; WX 667 ; N Ccircumflex ; B 66 -18 689 872 ;
-C -1 ; WX 444 ; N ccircumflex ; B 30 -11 449 660 ;
-C -1 ; WX 667 ; N Cdotaccent ; B 66 -18 689 801 ;
-C -1 ; WX 444 ; N cdotaccent ; B 30 -11 425 589 ;
-C -1 ; WX 611 ; N Ebreve ; B -8 0 627 861 ;
-C -1 ; WX 444 ; N ebreve ; B 31 -11 500 649 ;
-C -1 ; WX 722 ; N Gcircumflex ; B 52 -18 722 872 ;
-C -1 ; WX 500 ; N gcircumflex ; B 8 -206 495 660 ;
-C -1 ; WX 722 ; N Gdotaccent ; B 52 -18 722 801 ;
-C -1 ; WX 500 ; N gdotaccent ; B 8 -206 472 589 ;
-C -1 ; WX 722 ; N Hcircumflex ; B -8 0 767 872 ;
-C -1 ; WX 500 ; N hcircumflex ; B 19 -9 478 902 ;
-C -1 ; WX 722 ; N Hbar ; B -8 0 767 653 ;
-C -1 ; WX 500 ; N hbar ; B 19 -9 478 683 ;
-C -1 ; WX 333 ; N Itilde ; B -8 0 470 810 ;
-C -1 ; WX 278 ; N itilde ; B 49 -11 393 598 ;
-C -1 ; WX 333 ; N Ibreve ; B -8 0 485 861 ;
-C -1 ; WX 278 ; N ibreve ; B 49 -11 409 649 ;
-C -1 ; WX 707 ; N IJ ; B -8 -18 754 653 ;
-C -1 ; WX 474 ; N ij ; B 49 -207 462 654 ;
-C -1 ; WX 444 ; N Jcircumflex ; B -6 -18 491 872 ;
-C -1 ; WX 278 ; N jcircumflex ; B -124 -207 357 714 ;
-C -1 ; WX 491 ; N kgreenlandic ; B 14 0 503 460 ;
-C -1 ; WX 556 ; N Ldot ; B -8 0 559 653 ;
-C -1 ; WX 528 ; N ldot ; B 40 -11 459 683 ;
-C -1 ; WX 500 ; N napostrophe ; B 14 -9 474 666 ;
-C -1 ; WX 722 ; N Obreve ; B 60 -18 700 861 ;
-C -1 ; WX 500 ; N obreve ; B 27 -11 519 649 ;
-C -1 ; WX 500 ; N Scircumflex ; B 17 -18 529 872 ;
-C -1 ; WX 389 ; N scircumflex ; B 16 -13 417 660 ;
-C -1 ; WX 556 ; N Tbar ; B 59 0 633 653 ;
-C -1 ; WX 278 ; N tbar ; B 13 -11 296 546 ;
-C -1 ; WX 722 ; N Utilde ; B 102 -18 765 810 ;
-C -1 ; WX 500 ; N utilde ; B 42 -11 509 598 ;
-C -1 ; WX 722 ; N Ubreve ; B 102 -18 765 861 ;
-C -1 ; WX 500 ; N ubreve ; B 42 -11 525 649 ;
-C -1 ; WX 833 ; N Wcircumflex ; B 71 -18 906 872 ;
-C -1 ; WX 667 ; N wcircumflex ; B 16 -18 648 660 ;
-C -1 ; WX 556 ; N Ycircumflex ; B 78 0 633 872 ;
-C -1 ; WX 444 ; N ycircumflex ; B -24 -206 426 660 ;
-C -1 ; WX 278 ; N longs ; B -147 -207 424 678 ;
-C -1 ; WX 1023 ; N afii61352 ; B 9 -15 1007 669 ;
-C -1 ; WX 677 ; N infinity ; B 17 53 663 434 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 984
-KPX quoteright y -28
-KPX quoteright w -26
-KPX quoteright v -28
-KPX quoteright t -49
-KPX quoteright s -63
-KPX quoteright r -57
-KPX quoteright period -78
-KPX quoteright o -78
-KPX quoteright d -79
-KPX quoteright comma -73
-KPX quoteright Aring -87
-KPX quoteright Adieresis -87
-KPX quoteright Aacute -87
-KPX quoteright AE -140
-KPX quoteright A -87
-KPX comma quoteright -39
-KPX comma quotedblright -39
-KPX comma one -40
-KPX hyphen Y -53
-KPX hyphen W -34
-KPX hyphen V -43
-KPX hyphen T -46
-KPX hyphen Aring 3
-KPX hyphen Adieresis 3
-KPX hyphen Aacute 3
-KPX hyphen AE -23
-KPX hyphen A 3
-KPX period quoteright -38
-KPX period quotedblright -38
-KPX period one -39
-KPX zero seven -3
-KPX zero one -50
-KPX zero four 14
-KPX one zero -41
-KPX one two -50
-KPX one three -55
-KPX one six -50
-KPX one seven -60
-KPX one period -56
-KPX one one -69
-KPX one nine -61
-KPX one four -69
-KPX one five -55
-KPX one eight -57
-KPX one comma -52
-KPX two seven -22
-KPX two one -45
-KPX two four -12
-KPX three seven -15
-KPX three one -76
-KPX three four -9
-KPX four seven -27
-KPX four one -69
-KPX four four 12
-KPX five seven -28
-KPX five one -71
-KPX five four -5
-KPX six seven -37
-KPX six one -64
-KPX six four 17
-KPX seven two -13
-KPX seven three -42
-KPX seven six -37
-KPX seven seven -11
-KPX seven period -83
-KPX seven one -47
-KPX seven four -65
-KPX seven five -53
-KPX seven eight -32
-KPX seven comma -79
-KPX seven colon -88
-KPX eight seven -1
-KPX eight one -50
-KPX eight four 13
-KPX nine seven -5
-KPX nine one -64
-KPX nine four 2
-KPX A y -57
-KPX A w -44
-KPX A v -50
-KPX A u -9
-KPX A t -6
-KPX A quoteright -92
-KPX A quotedblright -92
-KPX A q -12
-KPX A period 8
-KPX A o -17
-KPX A hyphen -13
-KPX A guilsinglleft -43
-KPX A guillemotleft -44
-KPX A g -25
-KPX A e -17
-KPX A d -4
-KPX A comma 8
-KPX A ccedilla -28
-KPX A c -18
-KPX A a -4
-KPX A Y -21
-KPX A W -75
-KPX A V -81
-KPX A Ugrave -57
-KPX A Udieresis -57
-KPX A Ucircumflex -57
-KPX A Uacute -57
-KPX A U -57
-KPX A T -14
-KPX A Q -44
-KPX A Odieresis -45
-KPX A O -45
-KPX A G -44
-KPX A Ccedilla -50
-KPX A C -50
-KPX B Y -39
-KPX B W -29
-KPX B V -32
-KPX B Oslash -14
-KPX B Ograve -14
-KPX B Odieresis -14
-KPX B Ocircumflex -14
-KPX B Oacute -14
-KPX B OE -6
-KPX B O -14
-KPX B Atilde -23
-KPX B Aring -23
-KPX B Adieresis -23
-KPX B Acircumflex -23
-KPX B Aacute -23
-KPX B AE -35
-KPX B A -23
-KPX C Odieresis -19
-KPX C Oacute -19
-KPX C O -19
-KPX C K -21
-KPX C H -13
-KPX C Aring -14
-KPX C Adieresis -14
-KPX C Aacute -14
-KPX C AE -30
-KPX C A -14
-KPX D Y -50
-KPX D X -40
-KPX D W -36
-KPX D V -42
-KPX D T -9
-KPX D J -32
-KPX D Atilde -36
-KPX D Aring -36
-KPX D Agrave -36
-KPX D Adieresis -36
-KPX D Acircumflex -36
-KPX D Aacute -36
-KPX D A -36
-KPX F u -50
-KPX F r -52
-KPX F period -99
-KPX F oslash -80
-KPX F oe -75
-KPX F odieresis -52
-KPX F oacute -79
-KPX F o -79
-KPX F j -41
-KPX F i -36
-KPX F hyphen -45
-KPX F eacute -83
-KPX F e -83
-KPX F comma -95
-KPX F aring -70
-KPX F ae -82
-KPX F adieresis -52
-KPX F aacute -78
-KPX F a -77
-KPX F Odieresis -40
-KPX F O -40
-KPX F J -60
-KPX F Atilde -72
-KPX F Aring -72
-KPX F Agrave -72
-KPX F Adieresis -72
-KPX F Acircumflex -72
-KPX F Aacute -72
-KPX F A -72
-KPX G Y -12
-KPX G W -2
-KPX G V -5
-KPX G T -13
-KPX G Atilde -17
-KPX G Aring -17
-KPX G Agrave -17
-KPX G Adieresis -17
-KPX G Acircumflex -17
-KPX G Aacute -17
-KPX G AE -29
-KPX G A -17
-KPX J Aring -40
-KPX J Adieresis -40
-KPX J AE -52
-KPX J A -40
-KPX K y -89
-KPX K udieresis -10
-KPX K u -10
-KPX K odieresis -18
-KPX K oacute -18
-KPX K o -18
-KPX K hyphen -57
-KPX K e -18
-KPX K aring -5
-KPX K ae -5
-KPX K adieresis -5
-KPX K a -5
-KPX K T 21
-KPX K S 6
-KPX K Odieresis -46
-KPX K Oacute -46
-KPX K OE -45
-KPX K O -46
-KPX K G -53
-KPX K C -55
-KPX L y -26
-KPX L udieresis 10
-KPX L u 12
-KPX L quoteright -92
-KPX L quotedblright -92
-KPX L hyphen 47
-KPX L Y -20
-KPX L W -48
-KPX L V -55
-KPX L Udieresis -8
-KPX L U -8
-KPX L T -13
-KPX L S 20
-KPX L Otilde 10
-KPX L Ograve 10
-KPX L Odieresis 10
-KPX L Ocircumflex 10
-KPX L Oacute 10
-KPX L O 10
-KPX L G 11
-KPX L Ccedilla 4
-KPX L C 6
-KPX L Aring 44
-KPX L Adieresis 44
-KPX L Aacute 44
-KPX L AE 32
-KPX L A 44
-KPX N udieresis -25
-KPX N u -24
-KPX N period -16
-KPX N oslash -27
-KPX N odieresis -27
-KPX N oacute -27
-KPX N o -25
-KPX N eacute -30
-KPX N e -28
-KPX N comma -13
-KPX N aring -23
-KPX N ae -27
-KPX N adieresis -23
-KPX N aacute -23
-KPX N a -22
-KPX N Odieresis -20
-KPX N Oacute -20
-KPX N O -20
-KPX N G -14
-KPX N Ccedilla -20
-KPX N C -21
-KPX N Aring -20
-KPX N Adieresis -20
-KPX N Aacute -20
-KPX N AE -32
-KPX N A -20
-KPX O Y -51
-KPX O X -41
-KPX O W -39
-KPX O V -45
-KPX O T -3
-KPX O Aring -38
-KPX O Adieresis -38
-KPX O Aacute -38
-KPX O AE -70
-KPX O A -38
-KPX P period -121
-KPX P oslash -74
-KPX P oe -67
-KPX P odieresis -64
-KPX P oacute -73
-KPX P o -73
-KPX P hyphen -64
-KPX P eacute -79
-KPX P e -79
-KPX P comma -118
-KPX P aring -74
-KPX P ae -80
-KPX P adieresis -64
-KPX P aacute -74
-KPX P a -74
-KPX P J -89
-KPX P Aring -79
-KPX P Adieresis -79
-KPX P Aacute -79
-KPX P AE -116
-KPX P A -79
-KPX R udieresis -7
-KPX R uacute -7
-KPX R u -7
-KPX R oe -15
-KPX R odieresis -15
-KPX R oacute -15
-KPX R o -15
-KPX R hyphen -29
-KPX R eacute -15
-KPX R e -15
-KPX R aring -3
-KPX R ae -3
-KPX R adieresis -3
-KPX R aacute -3
-KPX R a -3
-KPX R Y -19
-KPX R W -28
-KPX R V -31
-KPX R Udieresis -36
-KPX R U -36
-KPX R Odieresis -26
-KPX R Oacute -26
-KPX R OE -18
-KPX R O -26
-KPX R G -20
-KPX R Ccedilla -25
-KPX R C -26
-KPX S t -13
-KPX S Y -1
-KPX S W 8
-KPX S V 5
-KPX S T 1
-KPX S Aring -2
-KPX S Adieresis -2
-KPX S Aacute -2
-KPX S AE -14
-KPX S A -2
-KPX T y -70
-KPX T w -69
-KPX T v -72
-KPX T u -86
-KPX T semicolon -92
-KPX T s -74
-KPX T r -87
-KPX T period -71
-KPX T oslash -89
-KPX T o -87
-KPX T j -20
-KPX T i -16
-KPX T hyphen -68
-KPX T guilsinglleft -101
-KPX T guillemotleft -102
-KPX T g -102
-KPX T e -90
-KPX T comma -70
-KPX T colon -84
-KPX T c -86
-KPX T ae -81
-KPX T a -81
-KPX T Y 33
-KPX T W 43
-KPX T V 41
-KPX T S -2
-KPX T Otilde -20
-KPX T Oslash -20
-KPX T Ograve -20
-KPX T Odieresis -20
-KPX T Ocircumflex -20
-KPX T Oacute -20
-KPX T OE -8
-KPX T O -20
-KPX T J -39
-KPX T G -7
-KPX T C -15
-KPX T Atilde -33
-KPX T Aring -33
-KPX T Agrave -33
-KPX T Adieresis -33
-KPX T Acircumflex -33
-KPX T Aacute -33
-KPX T AE -45
-KPX T A -33
-KPX U r -41
-KPX U period -39
-KPX U p -32
-KPX U n -29
-KPX U m -28
-KPX U comma -35
-KPX U Atilde -50
-KPX U Aring -50
-KPX U Adieresis -50
-KPX U Acircumflex -50
-KPX U Aacute -50
-KPX U AE -69
-KPX U A -50
-KPX V y -16
-KPX V u -40
-KPX V semicolon -79
-KPX V r -45
-KPX V period -80
-KPX V oslash -72
-KPX V o -70
-KPX V i -16
-KPX V hyphen -45
-KPX V guilsinglleft -81
-KPX V guillemotleft -82
-KPX V g -84
-KPX V e -74
-KPX V comma -76
-KPX V colon -82
-KPX V ae -72
-KPX V a -67
-KPX V T 32
-KPX V S -15
-KPX V Otilde -48
-KPX V Oslash -48
-KPX V Ograve -48
-KPX V Odieresis -48
-KPX V Ocircumflex -48
-KPX V Oacute -48
-KPX V O -48
-KPX V G -42
-KPX V C -48
-KPX V Atilde -66
-KPX V Aring -66
-KPX V Agrave -66
-KPX V Adieresis -66
-KPX V Acircumflex -66
-KPX V Aacute -66
-KPX V AE -102
-KPX V A -66
-KPX W y -11
-KPX W u -35
-KPX W semicolon -74
-KPX W r -40
-KPX W period -62
-KPX W oslash -58
-KPX W o -56
-KPX W i -18
-KPX W hyphen -32
-KPX W guilsinglleft -67
-KPX W guillemotleft -68
-KPX W g -75
-KPX W e -60
-KPX W comma -58
-KPX W colon -77
-KPX W ae -58
-KPX W a -53
-KPX W T 30
-KPX W S -17
-KPX W Otilde -39
-KPX W Oslash -39
-KPX W Ograve -39
-KPX W Odieresis -39
-KPX W Ocircumflex -39
-KPX W Oacute -39
-KPX W O -39
-KPX W G -33
-KPX W C -39
-KPX W Atilde -57
-KPX W Aring -57
-KPX W Agrave -57
-KPX W Adieresis -57
-KPX W Acircumflex -57
-KPX W Aacute -57
-KPX W AE -85
-KPX W A -57
-KPX X y -67
-KPX X u -7
-KPX X o -15
-KPX X hyphen -41
-KPX X e -15
-KPX X a -3
-KPX X Q -42
-KPX X Odieresis -44
-KPX X O -44
-KPX X C -50
-KPX Y v -32
-KPX Y u -58
-KPX Y semicolon -86
-KPX Y period -65
-KPX Y p -52
-KPX Y oslash -77
-KPX Y o -75
-KPX Y i -16
-KPX Y hyphen -60
-KPX Y guilsinglleft -92
-KPX Y guillemotleft -93
-KPX Y g -94
-KPX Y e -78
-KPX Y comma -64
-KPX Y colon -78
-KPX Y ae -75
-KPX Y a -72
-KPX Y T 32
-KPX Y S -15
-KPX Y Otilde -52
-KPX Y Oslash -52
-KPX Y Ograve -52
-KPX Y Odieresis -52
-KPX Y Ocircumflex -52
-KPX Y Oacute -52
-KPX Y O -52
-KPX Y G -45
-KPX Y C -52
-KPX Y Atilde -27
-KPX Y Aring -27
-KPX Y Agrave -27
-KPX Y Adieresis -27
-KPX Y Acircumflex -27
-KPX Y Aacute -27
-KPX Y AE -39
-KPX Y A -27
-KPX Z y -28
-KPX Z v -12
-KPX quoteleft Y -15
-KPX quoteleft W -5
-KPX quoteleft V -8
-KPX quoteleft T -9
-KPX quoteleft Aring -78
-KPX quoteleft Adieresis -78
-KPX quoteleft Aacute -78
-KPX quoteleft AE -131
-KPX quoteleft A -78
-KPX a y 2
-KPX a w 4
-KPX a v 1
-KPX a quoteright -28
-KPX a j -22
-KPX b y -3
-KPX b w -7
-KPX b v -10
-KPX c k -29
-KPX c h -30
-KPX e y 4
-KPX e x -10
-KPX e w 2
-KPX e t -16
-KPX e quoteright -21
-KPX f t 18
-KPX f s -20
-KPX f quoteright 18
-KPX f oslash -31
-KPX f oe -24
-KPX f odieresis -2
-KPX f oacute -30
-KPX f o -29
-KPX f l 42
-KPX f j 13
-KPX f i 17
-KPX f f 30
-KPX f eacute -34
-KPX f e -32
-KPX f aring -17
-KPX f ae -30
-KPX f adieresis -2
-KPX f aacute -27
-KPX f a -26
-KPX g r -21
-KPX g odieresis -41
-KPX g oacute -41
-KPX g l -46
-KPX g eacute -45
-KPX g e -45
-KPX g aring -42
-KPX g ae -46
-KPX g adieresis -42
-KPX g a -41
-KPX h y -4
-KPX h quoteright -31
-KPX i j -31
-KPX i T -10
-KPX k udieresis 8
-KPX k u 8
-KPX k s 7
-KPX k period 26
-KPX k odieresis 6
-KPX k oacute 6
-KPX k o 6
-KPX k hyphen -27
-KPX k g -27
-KPX k eacute 5
-KPX k e 5
-KPX k comma 27
-KPX k aring 12
-KPX k ae 9
-KPX k adieresis 12
-KPX k aacute 12
-KPX k a 12
-KPX l y -11
-KPX l v -12
-KPX m y -3
-KPX m w -4
-KPX m v -6
-KPX m p -4
-KPX n y -6
-KPX n w -7
-KPX n v -10
-KPX n quoteright -34
-KPX n p -7
-KPX n T -41
-KPX o y -10
-KPX o x -33
-KPX o w -15
-KPX o v -18
-KPX o t -15
-KPX o quoteright -24
-KPX o T -63
-KPX p y -4
-KPX p t -14
-KPX q u -11
-KPX q c -13
-KPX r y 33
-KPX r x 7
-KPX r w 32
-KPX r v 30
-KPX r u 11
-KPX r t 12
-KPX r semicolon -28
-KPX r s -17
-KPX r r 4
-KPX r quoteright -4
-KPX r q -31
-KPX r period -72
-KPX r p 13
-KPX r oslash -29
-KPX r ograve -28
-KPX r oe -23
-KPX r odieresis -28
-KPX r ocircumflex -28
-KPX r oacute -28
-KPX r o -28
-KPX r n 16
-KPX r m 17
-KPX r l -21
-KPX r k -15
-KPX r j 4
-KPX r i 8
-KPX r hyphen -52
-KPX r h -17
-KPX r g -21
-KPX r f 23
-KPX r egrave -35
-KPX r ecircumflex -35
-KPX r eacute -35
-KPX r e -35
-KPX r d -31
-KPX r comma -68
-KPX r colon -28
-KPX r ccedilla -17
-KPX r c -26
-KPX r aring -29
-KPX r agrave -29
-KPX r ae -36
-KPX r adieresis -29
-KPX r acircumflex -29
-KPX r aacute -29
-KPX r a -29
-KPX s t -12
-KPX s quoteright -20
-KPX t semicolon -26
-KPX t quoteright -19
-KPX t odieresis -11
-KPX t oacute -11
-KPX t o -11
-KPX t h -11
-KPX t eacute -13
-KPX t e -13
-KPX t colon -29
-KPX t aring -6
-KPX t ae -10
-KPX t adieresis -6
-KPX t aacute -6
-KPX t a -6
-KPX t S -9
-KPX u quoteright -31
-KPX v semicolon -48
-KPX v s -30
-KPX v period -51
-KPX v oslash -29
-KPX v ograve -28
-KPX v odieresis -28
-KPX v oacute -28
-KPX v o -26
-KPX v l -29
-KPX v g -36
-KPX v egrave -32
-KPX v ecircumflex -32
-KPX v eacute -32
-KPX v e -30
-KPX v comma -46
-KPX v colon -48
-KPX v c -26
-KPX v atilde -26
-KPX v aring -26
-KPX v agrave -26
-KPX v ae -29
-KPX v adieresis -26
-KPX v acircumflex -26
-KPX v aacute -26
-KPX v a -24
-KPX w semicolon -49
-KPX w s -32
-KPX w period -51
-KPX w oslash -31
-KPX w ograve -30
-KPX w odieresis -30
-KPX w oacute -30
-KPX w o -28
-KPX w l -30
-KPX w hyphen -4
-KPX w g -38
-KPX w egrave -34
-KPX w ecircumflex -34
-KPX w eacute -34
-KPX w e -32
-KPX w comma -47
-KPX w colon -49
-KPX w c -28
-KPX w atilde -28
-KPX w aring -28
-KPX w agrave -28
-KPX w ae -31
-KPX w adieresis -28
-KPX w acircumflex -28
-KPX w aacute -28
-KPX w a -26
-KPX x q 2
-KPX x o 1
-KPX x a 6
-KPX y semicolon -45
-KPX y s -19
-KPX y period -25
-KPX y oslash -16
-KPX y ograve -15
-KPX y odieresis -15
-KPX y oacute -15
-KPX y o -15
-KPX y l -18
-KPX y hyphen 7
-KPX y g -34
-KPX y egrave -19
-KPX y ecircumflex -19
-KPX y eacute -19
-KPX y e -19
-KPX y comma -21
-KPX y colon -48
-KPX y c -15
-KPX y atilde -12
-KPX y aring -12
-KPX y agrave -12
-KPX y ae -17
-KPX y adieresis -12
-KPX y acircumflex -12
-KPX y aacute -12
-KPX y a -12
-KPX quotedblleft Y -25
-KPX quotedblleft W -15
-KPX quotedblleft V -17
-KPX quotedblleft T -19
-KPX quotedblleft Aring -88
-KPX quotedblleft Adieresis -88
-KPX quotedblleft Aacute -88
-KPX quotedblleft AE -141
-KPX quotedblleft A -88
-KPX guilsinglright Y -80
-KPX guilsinglright W -66
-KPX guilsinglright V -75
-KPX guilsinglright T -76
-KPX guilsinglright Aring -24
-KPX guilsinglright Adieresis -24
-KPX guilsinglright Aacute -24
-KPX guilsinglright AE -50
-KPX guilsinglright A -24
-KPX quotedblbase Y -69
-KPX quotedblbase W -84
-KPX quotedblbase V -96
-KPX quotedblbase T -64
-KPX quotedblbase AE -13
-KPX quotedblbase A 1
-KPX quotedblright Y -30
-KPX quotedblright W -19
-KPX quotedblright V -22
-KPX quotedblright T -21
-KPX quotedblright Aring -94
-KPX quotedblright Adieresis -94
-KPX quotedblright Aacute -94
-KPX quotedblright AE -147
-KPX quotedblright A -94
-KPX guillemotright Y -81
-KPX guillemotright W -67
-KPX guillemotright V -76
-KPX guillemotright T -77
-KPX guillemotright Aring -25
-KPX guillemotright Adieresis -25
-KPX guillemotright Aacute -25
-KPX guillemotright AE -51
-KPX guillemotright A -25
-KPX Oslash A -38
-KPX ae y 6
-KPX ae w 5
-KPX ae v 2
-KPX Adieresis y -57
-KPX Adieresis w -44
-KPX Adieresis v -50
-KPX Adieresis u -9
-KPX Adieresis t -6
-KPX Adieresis quoteright -92
-KPX Adieresis quotedblright -92
-KPX Adieresis q -12
-KPX Adieresis period 8
-KPX Adieresis o -17
-KPX Adieresis hyphen -13
-KPX Adieresis guilsinglleft -43
-KPX Adieresis guillemotleft -44
-KPX Adieresis g -25
-KPX Adieresis d -4
-KPX Adieresis comma 8
-KPX Adieresis c -18
-KPX Adieresis a -4
-KPX Adieresis Y -21
-KPX Adieresis W -75
-KPX Adieresis V -81
-KPX Adieresis U -57
-KPX Adieresis T -14
-KPX Adieresis Q -44
-KPX Adieresis O -45
-KPX Adieresis G -44
-KPX Adieresis C -50
-KPX Aacute y -57
-KPX Aacute w -44
-KPX Aacute v -50
-KPX Aacute u -9
-KPX Aacute t -6
-KPX Aacute quoteright -92
-KPX Aacute q -12
-KPX Aacute period 8
-KPX Aacute o -17
-KPX Aacute hyphen -13
-KPX Aacute guilsinglleft -43
-KPX Aacute guillemotleft -44
-KPX Aacute g -25
-KPX Aacute e -17
-KPX Aacute d -4
-KPX Aacute comma 8
-KPX Aacute c -18
-KPX Aacute a -4
-KPX Aacute Y -21
-KPX Aacute W -75
-KPX Aacute V -81
-KPX Aacute U -57
-KPX Aacute T -14
-KPX Aacute Q -44
-KPX Aacute O -45
-KPX Aacute G -44
-KPX Aacute C -50
-KPX Agrave period 8
-KPX Agrave comma 8
-KPX Agrave Y -21
-KPX Agrave W -75
-KPX Agrave V -81
-KPX Agrave U -57
-KPX Agrave T -14
-KPX Agrave Q -44
-KPX Agrave O -45
-KPX Agrave G -44
-KPX Agrave C -50
-KPX Acircumflex period 8
-KPX Acircumflex comma 8
-KPX Acircumflex Y -21
-KPX Acircumflex W -75
-KPX Acircumflex V -81
-KPX Acircumflex U -57
-KPX Acircumflex T -14
-KPX Acircumflex Q -44
-KPX Acircumflex O -45
-KPX Acircumflex G -44
-KPX Acircumflex C -50
-KPX Atilde period 7
-KPX Atilde comma 7
-KPX Atilde Y -21
-KPX Atilde W -75
-KPX Atilde V -81
-KPX Atilde U -57
-KPX Atilde T -14
-KPX Atilde Q -44
-KPX Atilde O -45
-KPX Atilde G -44
-KPX Atilde C -50
-KPX Aring y -57
-KPX Aring w -44
-KPX Aring v -50
-KPX Aring u -9
-KPX Aring t -6
-KPX Aring quoteright -92
-KPX Aring quotedblright -92
-KPX Aring q -12
-KPX Aring period 8
-KPX Aring o -17
-KPX Aring hyphen -13
-KPX Aring guilsinglleft -43
-KPX Aring guillemotleft -44
-KPX Aring g -25
-KPX Aring e -17
-KPX Aring d -4
-KPX Aring comma 8
-KPX Aring c -18
-KPX Aring a -4
-KPX Aring Y -21
-KPX Aring W -75
-KPX Aring V -81
-KPX Aring U -57
-KPX Aring T -14
-KPX Aring Q -44
-KPX Aring O -45
-KPX Aring G -44
-KPX Aring C -50
-KPX Ccedilla A -18
-KPX Odieresis Y -51
-KPX Odieresis X -41
-KPX Odieresis W -39
-KPX Odieresis V -45
-KPX Odieresis T -3
-KPX Odieresis A -38
-KPX Oacute Y -51
-KPX Oacute W -39
-KPX Oacute V -45
-KPX Oacute T -3
-KPX Oacute A -38
-KPX Ograve Y -51
-KPX Ograve V -45
-KPX Ograve T -3
-KPX Ocircumflex Y -51
-KPX Ocircumflex V -45
-KPX Ocircumflex T -3
-KPX Otilde Y -51
-KPX Otilde V -45
-KPX Otilde T -3
-KPX Udieresis r -41
-KPX Udieresis period -39
-KPX Udieresis p -32
-KPX Udieresis n -29
-KPX Udieresis m -28
-KPX Udieresis comma -35
-KPX Udieresis b 1
-KPX Udieresis A -50
-KPX Uacute r -41
-KPX Uacute period -39
-KPX Uacute p -32
-KPX Uacute n -29
-KPX Uacute m -28
-KPX Uacute comma -35
-KPX Uacute A -50
-KPX Ugrave A -50
-KPX Ucircumflex A -50
-KPX adieresis y 2
-KPX adieresis w 4
-KPX adieresis v 1
-KPX aacute y 2
-KPX aacute w 4
-KPX aacute v 1
-KPX agrave y 2
-KPX agrave w 4
-KPX agrave v 1
-KPX aring y 2
-KPX aring w 4
-KPX aring v 1
-KPX eacute y 4
-KPX eacute w 2
-KPX ecircumflex y 4
-KPX ecircumflex w 2
-KPX odieresis y -10
-KPX odieresis x -33
-KPX odieresis w -15
-KPX odieresis v -18
-KPX odieresis t -16
-KPX oacute y -10
-KPX oacute w -15
-KPX oacute v -18
-KPX ograve y -10
-KPX ograve w -15
-KPX ograve v -18
-KPX ocircumflex t -16
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-roman-no-9-l/n021023l.pfb b/src/fonts/nimbus-roman-no-9-l/n021023l.pfb
deleted file mode 100644
index 911d62f..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021023l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-roman-no-9-l/n021023l.pfm b/src/fonts/nimbus-roman-no-9-l/n021023l.pfm
deleted file mode 100644
index 6f4015f..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021023l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-roman-no-9-l/n021024l.afm b/src/fonts/nimbus-roman-no-9-l/n021024l.afm
deleted file mode 100644
index 988bdef..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021024l.afm
+++ /dev/null
@@ -1,1546 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 14:01:04 2007
-FontName NimbusRomNo9L-MediItal
-FullName Nimbus Roman No9 L Medium Italic
-FamilyName Nimbus Roman No9 L
-Weight Bold
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle -15.3
-IsFixedPitch false
-UnderlinePosition -100
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -200 -324 1230 964
-CapHeight 669
-XHeight 462
-Ascender 699
-Descender -205
-StartCharMetrics 534
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 389 ; N exclam ; B 67 -13 370 684 ;
-C 34 ; WX 555 ; N quotedbl ; B 136 398 536 685 ;
-C 35 ; WX 500 ; N numbersign ; B -33 0 533 700 ;
-C 36 ; WX 500 ; N dollar ; B -20 -100 497 733 ;
-C 37 ; WX 833 ; N percent ; B 39 -10 793 692 ;
-C 38 ; WX 778 ; N ampersand ; B 5 -19 699 682 ;
-C 39 ; WX 333 ; N quoteright ; B 98 369 302 685 ;
-C 40 ; WX 333 ; N parenleft ; B 28 -179 344 685 ;
-C 41 ; WX 333 ; N parenright ; B -44 -179 271 685 ;
-C 42 ; WX 500 ; N asterisk ; B 65 252 456 685 ;
-C 43 ; WX 570 ; N plus ; B 33 0 537 506 ;
-C 44 ; WX 250 ; N comma ; B -60 -182 144 134 ;
-C 45 ; WX 333 ; N hyphen ; B 2 166 271 282 ;
-C 46 ; WX 250 ; N period ; B -9 -13 139 135 ;
-C 47 ; WX 278 ; N slash ; B -64 -18 342 685 ;
-C 48 ; WX 500 ; N zero ; B 17 -14 477 683 ;
-C 49 ; WX 500 ; N one ; B 5 0 419 683 ;
-C 50 ; WX 500 ; N two ; B -27 0 446 683 ;
-C 51 ; WX 500 ; N three ; B -15 -13 450 683 ;
-C 52 ; WX 500 ; N four ; B -15 0 503 683 ;
-C 53 ; WX 500 ; N five ; B -11 -13 487 669 ;
-C 54 ; WX 500 ; N six ; B 23 -15 509 679 ;
-C 55 ; WX 500 ; N seven ; B 52 0 525 669 ;
-C 56 ; WX 500 ; N eight ; B 3 -13 476 683 ;
-C 57 ; WX 500 ; N nine ; B -12 -10 475 683 ;
-C 58 ; WX 333 ; N colon ; B 23 -13 264 459 ;
-C 59 ; WX 333 ; N semicolon ; B -25 -183 264 459 ;
-C 60 ; WX 570 ; N less ; B 31 -12 539 518 ;
-C 61 ; WX 570 ; N equal ; B 33 107 537 399 ;
-C 62 ; WX 570 ; N greater ; B 31 -12 539 518 ;
-C 63 ; WX 500 ; N question ; B 79 -13 470 684 ;
-C 64 ; WX 832 ; N at ; B 63 -18 770 685 ;
-C 65 ; WX 667 ; N A ; B -67 0 593 683 ;
-C 66 ; WX 667 ; N B ; B -24 0 624 669 ;
-C 67 ; WX 667 ; N C ; B 32 -18 677 685 ;
-C 68 ; WX 722 ; N D ; B -46 0 685 669 ;
-C 69 ; WX 667 ; N E ; B -27 0 653 669 ;
-C 70 ; WX 667 ; N F ; B -13 0 660 669 ;
-C 71 ; WX 722 ; N G ; B 21 -18 706 685 ;
-C 72 ; WX 778 ; N H ; B -24 0 799 669 ;
-C 73 ; WX 389 ; N I ; B -32 0 406 669 ; L J IJ ;
-C 74 ; WX 500 ; N J ; B -46 -99 524 669 ;
-C 75 ; WX 667 ; N K ; B -21 0 702 669 ;
-C 76 ; WX 611 ; N L ; B -22 0 590 669 ; L periodcentered Ldot ;
-C 77 ; WX 889 ; N M ; B -29 -12 917 669 ;
-C 78 ; WX 722 ; N N ; B -27 -15 748 669 ; L o afii61352 ;
-C 79 ; WX 722 ; N O ; B 27 -18 691 685 ;
-C 80 ; WX 611 ; N P ; B -27 0 613 669 ;
-C 81 ; WX 722 ; N Q ; B 27 -208 691 685 ;
-C 82 ; WX 667 ; N R ; B -29 0 623 669 ;
-C 83 ; WX 556 ; N S ; B 2 -18 526 685 ;
-C 84 ; WX 611 ; N T ; B 50 0 650 669 ; L M trademark ;
-C 85 ; WX 722 ; N U ; B 67 -18 744 669 ;
-C 86 ; WX 667 ; N V ; B 65 -18 715 669 ;
-C 87 ; WX 889 ; N W ; B 65 -18 940 669 ;
-C 88 ; WX 667 ; N X ; B -24 0 694 669 ;
-C 89 ; WX 611 ; N Y ; B 73 0 659 669 ;
-C 90 ; WX 611 ; N Z ; B -11 0 590 669 ;
-C 91 ; WX 333 ; N bracketleft ; B -37 -159 362 674 ;
-C 92 ; WX 278 ; N backslash ; B -1 -18 279 685 ;
-C 93 ; WX 333 ; N bracketright ; B -56 -157 343 674 ;
-C 94 ; WX 570 ; N asciicircum ; B 67 304 503 669 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 128 369 332 685 ;
-C 97 ; WX 500 ; N a ; B -21 -14 455 462 ;
-C 98 ; WX 500 ; N b ; B -14 -13 444 699 ;
-C 99 ; WX 444 ; N c ; B -5 -13 392 462 ;
-C 100 ; WX 500 ; N d ; B -21 -13 517 699 ;
-C 101 ; WX 444 ; N e ; B 5 -13 398 462 ;
-C 102 ; WX 333 ; N f ; B -169 -205 446 698 ; L l fl ; L i fi ;
-C 103 ; WX 500 ; N g ; B -52 -203 478 462 ;
-C 104 ; WX 556 ; N h ; B -13 -9 498 699 ;
-C 105 ; WX 278 ; N i ; B 2 -9 263 685 ; L j ij ;
-C 106 ; WX 278 ; N j ; B -189 -207 279 685 ;
-C 107 ; WX 500 ; N k ; B -23 -8 483 699 ;
-C 108 ; WX 278 ; N l ; B 2 -9 290 699 ; L periodcentered ldot ;
-C 109 ; WX 778 ; N m ; B -14 -9 722 462 ;
-C 110 ; WX 556 ; N n ; B -6 -9 493 462 ;
-C 111 ; WX 500 ; N o ; B -3 -13 441 462 ;
-C 112 ; WX 500 ; N p ; B -120 -205 446 462 ;
-C 113 ; WX 500 ; N q ; B 1 -205 471 462 ;
-C 114 ; WX 389 ; N r ; B -21 0 389 462 ;
-C 115 ; WX 389 ; N s ; B -19 -13 333 462 ;
-C 116 ; WX 278 ; N t ; B -11 -9 281 594 ;
-C 117 ; WX 556 ; N u ; B 15 -9 492 462 ;
-C 118 ; WX 444 ; N v ; B 16 -13 401 462 ;
-C 119 ; WX 667 ; N w ; B 16 -13 614 462 ;
-C 120 ; WX 500 ; N x ; B -46 -13 469 462 ;
-C 121 ; WX 444 ; N y ; B -94 -205 392 462 ;
-C 122 ; WX 389 ; N z ; B -43 -78 368 449 ;
-C 123 ; WX 348 ; N braceleft ; B 5 -187 436 686 ;
-C 124 ; WX 220 ; N bar ; B 66 -18 154 685 ;
-C 125 ; WX 348 ; N braceright ; B -129 -187 302 686 ;
-C 126 ; WX 570 ; N asciitilde ; B 54 175 516 331 ;
-C 161 ; WX 389 ; N exclamdown ; B 19 -205 320 494 ;
-C 162 ; WX 500 ; N cent ; B 42 -143 439 576 ;
-C 163 ; WX 500 ; N sterling ; B -32 -12 510 683 ;
-C 164 ; WX 167 ; N fraction ; B -169 -14 324 683 ;
-C 165 ; WX 500 ; N yen ; B 33 0 628 669 ;
-C 166 ; WX 500 ; N florin ; B -87 -156 537 707 ;
-C 167 ; WX 500 ; N section ; B 36 -143 459 685 ;
-C 168 ; WX 500 ; N currency ; B -26 34 526 586 ;
-C 169 ; WX 278 ; N quotesingle ; B 128 398 268 685 ;
-C 170 ; WX 500 ; N quotedblleft ; B 53 369 513 685 ;
-C 171 ; WX 500 ; N guillemotleft ; B 12 32 468 415 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 32 32 303 415 ;
-C 173 ; WX 333 ; N guilsinglright ; B 10 32 281 415 ;
-C 174 ; WX 556 ; N fi ; B -188 -205 514 703 ;
-C 175 ; WX 556 ; N fl ; B -186 -205 553 704 ;
-C 177 ; WX 500 ; N endash ; B -40 178 477 269 ;
-C 178 ; WX 500 ; N dagger ; B 91 -145 494 685 ;
-C 179 ; WX 500 ; N daggerdbl ; B 10 -139 493 685 ;
-C 180 ; WX 250 ; N periodcentered ; B 51 257 199 405 ;
-C 182 ; WX 500 ; N paragraph ; B -57 -193 562 669 ;
-C 183 ; WX 350 ; N bullet ; B 0 175 350 525 ;
-C 184 ; WX 333 ; N quotesinglbase ; B -5 -182 199 134 ;
-C 185 ; WX 500 ; N quotedblbase ; B -57 -182 403 134 ;
-C 186 ; WX 500 ; N quotedblright ; B 53 369 513 685 ;
-C 187 ; WX 500 ; N guillemotright ; B 12 32 468 415 ;
-C 188 ; WX 1000 ; N ellipsis ; B 40 -13 852 135 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -29 996 706 ;
-C 191 ; WX 500 ; N questiondown ; B 30 -205 421 492 ;
-C 193 ; WX 333 ; N grave ; B 85 516 297 697 ;
-C 194 ; WX 333 ; N acute ; B 139 516 379 697 ;
-C 195 ; WX 333 ; N circumflex ; B 40 516 367 690 ;
-C 196 ; WX 333 ; N tilde ; B 48 536 407 655 ;
-C 197 ; WX 333 ; N macron ; B 51 553 393 623 ;
-C 198 ; WX 333 ; N breve ; B 71 516 387 678 ;
-C 199 ; WX 333 ; N dotaccent ; B 163 525 293 655 ;
-C 200 ; WX 333 ; N dieresis ; B 55 525 397 655 ;
-C 202 ; WX 333 ; N ring ; B 127 540 340 754 ;
-C 203 ; WX 333 ; N cedilla ; B -80 -218 156 5 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 69 516 498 697 ;
-C 206 ; WX 333 ; N ogonek ; B -40 -173 189 44 ;
-C 207 ; WX 333 ; N caron ; B 79 516 411 690 ;
-C 208 ; WX 1000 ; N emdash ; B -40 178 977 269 ;
-C 225 ; WX 944 ; N AE ; B -64 0 918 669 ;
-C 227 ; WX 266 ; N ordfeminine ; B 16 399 330 685 ;
-C 232 ; WX 611 ; N Lslash ; B -22 0 590 669 ;
-C 233 ; WX 722 ; N Oslash ; B 27 -125 691 764 ;
-C 234 ; WX 944 ; N OE ; B 23 -9 946 677 ;
-C 235 ; WX 300 ; N ordmasculine ; B 56 400 348 685 ;
-C 241 ; WX 722 ; N ae ; B -5 -13 673 462 ;
-C 245 ; WX 278 ; N dotlessi ; B 2 -9 238 462 ;
-C 248 ; WX 278 ; N lslash ; B -13 -9 301 699 ;
-C 249 ; WX 500 ; N oslash ; B -3 -119 441 560 ;
-C 250 ; WX 722 ; N oe ; B 6 -13 674 462 ;
-C 251 ; WX 500 ; N germandbls ; B -200 -200 473 705 ;
-C -1 ; WX 667 ; N Adieresis ; B -67 0 593 862 ;
-C -1 ; WX 667 ; N Aacute ; B -67 0 593 904 ;
-C -1 ; WX 667 ; N Agrave ; B -67 0 593 904 ;
-C -1 ; WX 667 ; N Acircumflex ; B -67 0 593 897 ;
-C -1 ; WX 667 ; N Abreve ; B -67 0 593 888 ;
-C -1 ; WX 667 ; N Atilde ; B -67 0 593 862 ;
-C -1 ; WX 667 ; N Aring ; B -67 0 593 950 ;
-C -1 ; WX 667 ; N Aogonek ; B -67 -173 729 683 ;
-C -1 ; WX 667 ; N Ccedilla ; B 32 -218 677 685 ;
-C -1 ; WX 667 ; N Cacute ; B 32 -18 677 907 ;
-C -1 ; WX 667 ; N Ccaron ; B 32 -18 677 900 ;
-C -1 ; WX 722 ; N Dcaron ; B -46 0 685 900 ;
-C -1 ; WX 667 ; N Edieresis ; B -27 0 653 862 ;
-C -1 ; WX 667 ; N Eacute ; B -27 0 653 904 ;
-C -1 ; WX 667 ; N Egrave ; B -27 0 653 904 ;
-C -1 ; WX 667 ; N Ecircumflex ; B -27 0 653 897 ;
-C -1 ; WX 667 ; N Ecaron ; B -27 0 653 900 ;
-C -1 ; WX 667 ; N Edotaccent ; B -27 0 653 865 ;
-C -1 ; WX 667 ; N Eogonek ; B -27 -173 667 669 ;
-C -1 ; WX 722 ; N Gbreve ; B 21 -18 706 888 ;
-C -1 ; WX 389 ; N Idieresis ; B -32 0 445 862 ;
-C -1 ; WX 389 ; N Iacute ; B -32 0 407 907 ;
-C -1 ; WX 389 ; N Igrave ; B -32 0 406 904 ;
-C -1 ; WX 389 ; N Icircumflex ; B -32 0 420 897 ;
-C -1 ; WX 389 ; N Idotaccent ; B -32 0 406 865 ;
-C -1 ; WX 611 ; N Lacute ; B -22 0 590 907 ;
-C -1 ; WX 611 ; N Lcaron ; B -22 0 651 685 ;
-C -1 ; WX 722 ; N Nacute ; B -27 -15 748 907 ;
-C -1 ; WX 722 ; N Ncaron ; B -27 -15 748 900 ;
-C -1 ; WX 722 ; N Ntilde ; B -27 -15 748 862 ;
-C -1 ; WX 722 ; N Odieresis ; B 27 -18 691 862 ;
-C -1 ; WX 722 ; N Oacute ; B 27 -18 691 904 ;
-C -1 ; WX 722 ; N Ograve ; B 27 -18 691 904 ;
-C -1 ; WX 722 ; N Ocircumflex ; B 27 -18 691 897 ;
-C -1 ; WX 722 ; N Otilde ; B 27 -18 691 862 ;
-C -1 ; WX 722 ; N Ohungarumlaut ; B 27 -18 693 907 ;
-C -1 ; WX 667 ; N Racute ; B -29 0 623 907 ;
-C -1 ; WX 667 ; N Rcaron ; B -29 0 623 900 ;
-C -1 ; WX 556 ; N Sacute ; B 2 -18 526 907 ;
-C -1 ; WX 556 ; N Scaron ; B 2 -18 526 897 ;
-C -1 ; WX 556 ; N Scedilla ; B 2 -218 526 685 ;
-C -1 ; WX 611 ; N Tcaron ; B 50 0 650 900 ;
-C -1 ; WX 722 ; N Udieresis ; B 67 -18 744 862 ;
-C -1 ; WX 722 ; N Uacute ; B 67 -18 744 904 ;
-C -1 ; WX 722 ; N Ugrave ; B 67 -18 744 904 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 67 -18 744 897 ;
-C -1 ; WX 722 ; N Uring ; B 67 -18 744 964 ;
-C -1 ; WX 722 ; N Uhungarumlaut ; B 67 -18 744 907 ;
-C -1 ; WX 611 ; N Yacute ; B 73 0 659 904 ;
-C -1 ; WX 611 ; N Zacute ; B -11 0 590 907 ;
-C -1 ; WX 611 ; N Zcaron ; B -11 0 590 897 ;
-C -1 ; WX 611 ; N Zdotaccent ; B -11 0 590 865 ;
-C -1 ; WX 667 ; N Amacron ; B -67 0 593 833 ;
-C -1 ; WX 611 ; N Tcommaaccent ; B 50 -324 650 669 ;
-C -1 ; WX 611 ; N Ydieresis ; B 73 0 659 862 ;
-C -1 ; WX 667 ; N Emacron ; B -27 0 653 833 ;
-C -1 ; WX 389 ; N Imacron ; B -32 0 461 833 ;
-C -1 ; WX 389 ; N Iogonek ; B -32 -173 406 669 ;
-C -1 ; WX 667 ; N Kcommaaccent ; B -21 -324 702 669 ;
-C -1 ; WX 611 ; N Lcommaaccent ; B -22 -324 590 669 ;
-C -1 ; WX 722 ; N Ncommaaccent ; B -27 -324 748 669 ;
-C -1 ; WX 722 ; N Omacron ; B 27 -18 691 833 ;
-C -1 ; WX 667 ; N Rcommaaccent ; B -29 -324 623 669 ;
-C -1 ; WX 722 ; N Gcommaaccent ; B 21 -324 706 685 ;
-C -1 ; WX 722 ; N Umacron ; B 67 -18 744 833 ;
-C -1 ; WX 722 ; N Uogonek ; B 67 -173 744 669 ;
-C -1 ; WX 500 ; N adieresis ; B -21 -14 471 655 ;
-C -1 ; WX 500 ; N aacute ; B -21 -14 463 697 ;
-C -1 ; WX 500 ; N agrave ; B -21 -14 455 697 ;
-C -1 ; WX 500 ; N acircumflex ; B -21 -14 455 690 ;
-C -1 ; WX 500 ; N abreve ; B -21 -14 470 678 ;
-C -1 ; WX 500 ; N atilde ; B -21 -14 491 655 ;
-C -1 ; WX 500 ; N aring ; B -21 -14 455 754 ;
-C -1 ; WX 500 ; N aogonek ; B -21 -173 500 462 ;
-C -1 ; WX 444 ; N cacute ; B -5 -13 444 697 ;
-C -1 ; WX 444 ; N ccaron ; B -5 -13 468 690 ;
-C -1 ; WX 444 ; N ccedilla ; B -24 -218 392 462 ;
-C -1 ; WX 600 ; N dcaron ; B -21 -13 664 699 ;
-C -1 ; WX 444 ; N edieresis ; B 5 -13 443 655 ;
-C -1 ; WX 444 ; N eacute ; B 5 -13 435 697 ;
-C -1 ; WX 444 ; N egrave ; B 5 -13 398 697 ;
-C -1 ; WX 444 ; N ecircumflex ; B 5 -13 423 690 ;
-C -1 ; WX 444 ; N ecaron ; B 5 -13 467 690 ;
-C -1 ; WX 444 ; N edotaccent ; B 5 -13 398 655 ;
-C -1 ; WX 444 ; N eogonek ; B 5 -173 404 462 ;
-C -1 ; WX 500 ; N gbreve ; B -52 -203 478 678 ;
-C -1 ; WX 278 ; N idieresis ; B 2 -9 360 655 ;
-C -1 ; WX 278 ; N iacute ; B 2 -9 352 697 ;
-C -1 ; WX 278 ; N igrave ; B 2 -9 260 697 ;
-C -1 ; WX 278 ; N icircumflex ; B -2 -9 325 690 ;
-C -1 ; WX 278 ; N lacute ; B 2 -9 392 907 ;
-C -1 ; WX 382 ; N lcaron ; B 2 -9 446 699 ;
-C -1 ; WX 556 ; N nacute ; B -6 -9 493 697 ;
-C -1 ; WX 556 ; N ncaron ; B -6 -9 523 690 ;
-C -1 ; WX 556 ; N ntilde ; B -6 -9 504 655 ;
-C -1 ; WX 500 ; N odieresis ; B -3 -13 466 655 ;
-C -1 ; WX 500 ; N oacute ; B -3 -13 463 697 ;
-C -1 ; WX 500 ; N ograve ; B -3 -13 441 697 ;
-C -1 ; WX 500 ; N ocircumflex ; B -3 -13 451 690 ;
-C -1 ; WX 500 ; N otilde ; B -3 -13 491 655 ;
-C -1 ; WX 500 ; N ohungarumlaut ; B -3 -13 582 697 ;
-C -1 ; WX 389 ; N racute ; B -21 0 407 697 ;
-C -1 ; WX 389 ; N sacute ; B -19 -13 407 697 ;
-C -1 ; WX 389 ; N scaron ; B -19 -13 439 690 ;
-C -1 ; WX 389 ; N scommaaccent ; B -26 -324 333 462 ;
-C -1 ; WX 345 ; N tcaron ; B -11 -9 409 685 ;
-C -1 ; WX 556 ; N udieresis ; B 15 -9 494 655 ;
-C -1 ; WX 556 ; N uacute ; B 15 -9 492 697 ;
-C -1 ; WX 556 ; N ugrave ; B 15 -9 492 697 ;
-C -1 ; WX 556 ; N ucircumflex ; B 15 -9 492 690 ;
-C -1 ; WX 556 ; N uring ; B 15 -9 492 754 ;
-C -1 ; WX 556 ; N uhungarumlaut ; B 15 -9 610 697 ;
-C -1 ; WX 444 ; N yacute ; B -94 -205 435 697 ;
-C -1 ; WX 389 ; N zacute ; B -43 -78 407 697 ;
-C -1 ; WX 389 ; N zcaron ; B -43 -78 424 690 ;
-C -1 ; WX 389 ; N zdotaccent ; B -43 -78 368 655 ;
-C -1 ; WX 444 ; N ydieresis ; B -94 -205 438 655 ;
-C -1 ; WX 278 ; N tcommaaccent ; B -81 -324 281 594 ;
-C -1 ; WX 500 ; N amacron ; B -21 -14 477 623 ;
-C -1 ; WX 444 ; N emacron ; B 5 -13 449 623 ;
-C -1 ; WX 278 ; N imacron ; B 2 -9 366 623 ;
-C -1 ; WX 500 ; N kcommaaccent ; B -23 -324 483 699 ;
-C -1 ; WX 278 ; N lcommaaccent ; B -81 -324 290 699 ;
-C -1 ; WX 556 ; N ncommaaccent ; B -6 -324 493 462 ;
-C -1 ; WX 500 ; N omacron ; B -3 -13 477 623 ;
-C -1 ; WX 389 ; N rcommaaccent ; B -80 -324 389 462 ;
-C -1 ; WX 556 ; N umacron ; B 15 -9 505 623 ;
-C -1 ; WX 556 ; N uogonek ; B 15 -173 556 462 ;
-C -1 ; WX 389 ; N rcaron ; B -21 0 439 690 ;
-C -1 ; WX 389 ; N scedilla ; B -40 -218 333 462 ;
-C -1 ; WX 500 ; N gcommaaccent ; B -52 -203 478 765 ;
-C -1 ; WX 278 ; N iogonek ; B 2 -173 278 685 ;
-C -1 ; WX 556 ; N Scommaaccent ; B 2 -324 526 685 ;
-C -1 ; WX 722 ; N Eth ; B -31 0 700 669 ;
-C -1 ; WX 722 ; N Dcroat ; B -31 0 700 669 ;
-C -1 ; WX 611 ; N Thorn ; B -27 0 574 669 ;
-C -1 ; WX 500 ; N dcroat ; B -21 -13 540 699 ;
-C -1 ; WX 500 ; N eth ; B -3 -13 454 699 ;
-C -1 ; WX 500 ; N thorn ; B -120 -205 446 699 ;
-C -1 ; WX 500 ; N Euro ; B 53 -5 666 689 ;
-C -1 ; WX 300 ; N onesuperior ; B 30 274 301 683 ;
-C -1 ; WX 300 ; N twosuperior ; B 2 274 313 683 ;
-C -1 ; WX 300 ; N threesuperior ; B 17 265 321 683 ;
-C -1 ; WX 400 ; N degree ; B 83 397 369 683 ;
-C -1 ; WX 606 ; N minus ; B 51 209 555 297 ;
-C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ;
-C -1 ; WX 570 ; N divide ; B 33 -29 537 535 ;
-C -1 ; WX 1000 ; N trademark ; B 32 263 968 669 ;
-C -1 ; WX 570 ; N plusminus ; B 33 0 537 568 ;
-C -1 ; WX 750 ; N onehalf ; B -9 -14 723 683 ;
-C -1 ; WX 750 ; N onequarter ; B 7 -14 721 683 ;
-C -1 ; WX 750 ; N threequarters ; B 7 -14 726 683 ;
-C -1 ; WX 333 ; N commaaccent ; B -54 -324 130 -40 ;
-C -1 ; WX 747 ; N copyright ; B 30 -18 718 685 ;
-C -1 ; WX 747 ; N registered ; B 30 -18 718 685 ;
-C -1 ; WX 494 ; N lozenge ; B 18 0 466 740 ;
-C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
-C -1 ; WX 570 ; N notequal ; B 33 -13 537 519 ;
-C -1 ; WX 549 ; N radical ; B -17 -35 535 916 ;
-C -1 ; WX 570 ; N lessequal ; B 31 0 539 642 ;
-C -1 ; WX 570 ; N greaterequal ; B 31 0 539 642 ;
-C -1 ; WX 606 ; N logicalnot ; B 51 108 555 399 ;
-C -1 ; WX 713 ; N summation ; B 14 -123 695 752 ;
-C -1 ; WX 494 ; N partialdiff ; B 16 -20 472 743 ;
-C -1 ; WX 220 ; N brokenbar ; B 66 -18 154 685 ;
-C -1 ; WX 576 ; N mu ; B -60 -207 516 449 ;
-C -1 ; WX 667 ; N afii10017 ; B -67 0 593 683 ;
-C -1 ; WX 733 ; N afii10018 ; B -24 0 726 669 ;
-C -1 ; WX 667 ; N afii10019 ; B -24 0 624 669 ;
-C -1 ; WX 656 ; N afii10020 ; B -24 0 649 669 ;
-C -1 ; WX 864 ; N afii10021 ; B -74 -167 885 669 ;
-C -1 ; WX 667 ; N afii10022 ; B -24 0 656 669 ;
-C -1 ; WX 667 ; N afii10023 ; B -24 0 656 862 ;
-C -1 ; WX 1107 ; N afii10024 ; B -24 0 1132 686 ;
-C -1 ; WX 657 ; N afii10025 ; B -18 -19 614 692 ;
-C -1 ; WX 870 ; N afii10026 ; B -24 0 891 669 ;
-C -1 ; WX 870 ; N afii10027 ; B -24 0 891 888 ;
-C -1 ; WX 775 ; N afii10028 ; B -24 0 796 686 ;
-C -1 ; WX 855 ; N afii10029 ; B -31 -14 876 669 ;
-C -1 ; WX 896 ; N afii10030 ; B -29 -12 917 669 ;
-C -1 ; WX 778 ; N afii10031 ; B -24 0 799 669 ;
-C -1 ; WX 722 ; N afii10032 ; B 27 -18 691 685 ;
-C -1 ; WX 869 ; N afii10033 ; B -24 0 890 669 ;
-C -1 ; WX 611 ; N afii10034 ; B -24 0 616 669 ;
-C -1 ; WX 667 ; N afii10035 ; B 32 -18 677 685 ;
-C -1 ; WX 611 ; N afii10036 ; B 50 0 650 669 ;
-C -1 ; WX 766 ; N afii10037 ; B 6 -14 793 669 ;
-C -1 ; WX 833 ; N afii10038 ; B 20 0 814 669 ;
-C -1 ; WX 667 ; N afii10039 ; B -24 0 694 669 ;
-C -1 ; WX 869 ; N afii10040 ; B -24 -167 890 669 ;
-C -1 ; WX 823 ; N afii10041 ; B 104 0 844 669 ;
-C -1 ; WX 1208 ; N afii10042 ; B -24 0 1229 669 ;
-C -1 ; WX 1209 ; N afii10043 ; B -24 -167 1230 669 ;
-C -1 ; WX 796 ; N afii10044 ; B 50 0 700 669 ;
-C -1 ; WX 1060 ; N afii10045 ; B -24 0 1081 670 ;
-C -1 ; WX 712 ; N afii10046 ; B -24 0 616 669 ;
-C -1 ; WX 732 ; N afii10047 ; B -8 -19 701 691 ;
-C -1 ; WX 1195 ; N afii10048 ; B -24 -18 1086 685 ;
-C -1 ; WX 821 ; N afii10049 ; B -24 0 842 669 ;
-C -1 ; WX 500 ; N afii10065 ; B -21 -14 455 462 ;
-C -1 ; WX 500 ; N afii10066 ; B -3 -14 556 690 ;
-C -1 ; WX 444 ; N afii10067 ; B 4 -13 388 462 ;
-C -1 ; WX 389 ; N afii10068 ; B 0 -13 353 462 ;
-C -1 ; WX 534 ; N afii10069 ; B -4 -14 515 675 ;
-C -1 ; WX 444 ; N afii10070 ; B 5 -13 398 462 ;
-C -1 ; WX 444 ; N afii10071 ; B 5 -13 443 655 ;
-C -1 ; WX 1051 ; N afii10072 ; B 3 -13 999 462 ;
-C -1 ; WX 439 ; N afii10073 ; B -12 -14 383 473 ;
-C -1 ; WX 556 ; N afii10074 ; B 15 -9 492 462 ;
-C -1 ; WX 556 ; N afii10075 ; B 15 -9 501 678 ;
-C -1 ; WX 534 ; N afii10076 ; B -6 0 514 470 ;
-C -1 ; WX 637 ; N afii10077 ; B 5 -10 573 449 ;
-C -1 ; WX 859 ; N afii10078 ; B 5 -18 795 449 ;
-C -1 ; WX 560 ; N afii10079 ; B -6 -9 496 461 ;
-C -1 ; WX 500 ; N afii10080 ; B -3 -13 441 462 ;
-C -1 ; WX 556 ; N afii10081 ; B -6 -9 493 462 ;
-C -1 ; WX 500 ; N afii10082 ; B -120 -205 446 462 ;
-C -1 ; WX 444 ; N afii10083 ; B -5 -13 392 462 ;
-C -1 ; WX 778 ; N afii10084 ; B -14 -9 722 462 ;
-C -1 ; WX 444 ; N afii10085 ; B -94 -205 392 462 ;
-C -1 ; WX 764 ; N afii10086 ; B 1 -205 710 698 ;
-C -1 ; WX 500 ; N afii10087 ; B -46 -13 469 462 ;
-C -1 ; WX 556 ; N afii10088 ; B 15 -122 492 462 ;
-C -1 ; WX 556 ; N afii10089 ; B 34 -9 492 462 ;
-C -1 ; WX 806 ; N afii10090 ; B 15 -9 742 462 ;
-C -1 ; WX 806 ; N afii10091 ; B 15 -122 742 462 ;
-C -1 ; WX 591 ; N afii10092 ; B 19 -13 544 473 ;
-C -1 ; WX 744 ; N afii10093 ; B 14 -13 680 462 ;
-C -1 ; WX 444 ; N afii10094 ; B 15 -13 395 461 ;
-C -1 ; WX 451 ; N afii10095 ; B -5 -13 392 462 ;
-C -1 ; WX 765 ; N afii10096 ; B -6 -13 706 462 ;
-C -1 ; WX 594 ; N afii10097 ; B 5 -10 530 449 ;
-C -1 ; WX 667 ; N uni0400 ; B -24 0 656 900 ;
-C -1 ; WX 728 ; N afii10051 ; B 50 -148 758 669 ;
-C -1 ; WX 667 ; N afii10052 ; B -13 0 660 937 ;
-C -1 ; WX 722 ; N afii10053 ; B 33 -19 765 691 ;
-C -1 ; WX 556 ; N afii10054 ; B 2 -18 526 685 ;
-C -1 ; WX 389 ; N afii10055 ; B -24 0 414 669 ;
-C -1 ; WX 389 ; N afii10056 ; B -24 0 453 862 ;
-C -1 ; WX 500 ; N afii10057 ; B -46 -99 524 669 ;
-C -1 ; WX 987 ; N afii10058 ; B -31 -14 997 669 ;
-C -1 ; WX 913 ; N afii10059 ; B -24 0 926 669 ;
-C -1 ; WX 788 ; N afii10060 ; B 50 0 771 669 ;
-C -1 ; WX 778 ; N afii10061 ; B -64 0 756 937 ;
-C -1 ; WX 870 ; N uni040D ; B -24 0 891 900 ;
-C -1 ; WX 722 ; N afii10062 ; B 6 -14 808 888 ;
-C -1 ; WX 869 ; N afii10145 ; B -24 -228 890 669 ;
-C -1 ; WX 444 ; N uni0450 ; B 5 -13 405 693 ;
-C -1 ; WX 451 ; N afii10099 ; B -13 -203 478 699 ;
-C -1 ; WX 458 ; N afii10100 ; B -42 0 486 697 ;
-C -1 ; WX 444 ; N afii10101 ; B 11 -14 456 473 ;
-C -1 ; WX 389 ; N afii10102 ; B -19 -13 333 462 ;
-C -1 ; WX 278 ; N afii10103 ; B 2 -9 263 685 ;
-C -1 ; WX 278 ; N afii10104 ; B 2 -9 382 642 ;
-C -1 ; WX 278 ; N afii10105 ; B -189 -207 279 685 ;
-C -1 ; WX 731 ; N afii10106 ; B 5 -13 750 449 ;
-C -1 ; WX 658 ; N afii10107 ; B -6 -13 671 461 ;
-C -1 ; WX 556 ; N afii10108 ; B -13 -9 498 699 ;
-C -1 ; WX 558 ; N afii10109 ; B -6 0 514 697 ;
-C -1 ; WX 556 ; N uni045D ; B 15 -9 492 693 ;
-C -1 ; WX 444 ; N afii10110 ; B -94 -205 438 678 ;
-C -1 ; WX 556 ; N afii10193 ; B 15 -122 492 462 ;
-C -1 ; WX 712 ; N uni048C ; B -24 0 616 669 ;
-C -1 ; WX 444 ; N uni048D ; B -5 -13 395 461 ;
-C -1 ; WX 611 ; N uni048E ; B -24 0 616 669 ;
-C -1 ; WX 500 ; N uni048F ; B -120 -205 446 462 ;
-C -1 ; WX 611 ; N afii10050 ; B -99 0 698 842 ;
-C -1 ; WX 458 ; N afii10098 ; B -57 0 508 571 ;
-C -1 ; WX 667 ; N uni0492 ; B -13 0 660 669 ;
-C -1 ; WX 389 ; N uni0493 ; B 0 -13 353 462 ;
-C -1 ; WX 667 ; N uni0494 ; B -13 -165 662 669 ;
-C -1 ; WX 1107 ; N uni0496 ; B -24 -167 1132 686 ;
-C -1 ; WX 1051 ; N uni0497 ; B 3 -122 999 462 ;
-C -1 ; WX 657 ; N uni0498 ; B -18 -194 614 692 ;
-C -1 ; WX 439 ; N uni0499 ; B -12 -194 383 473 ;
-C -1 ; WX 772 ; N uni049A ; B -24 -167 796 686 ;
-C -1 ; WX 534 ; N uni049B ; B -6 -122 514 470 ;
-C -1 ; WX 772 ; N uni049E ; B -24 0 796 686 ;
-C -1 ; WX 534 ; N uni049F ; B -6 0 514 470 ;
-C -1 ; WX 778 ; N uni04A2 ; B -24 -167 799 669 ;
-C -1 ; WX 560 ; N uni04A3 ; B -6 -122 496 461 ;
-C -1 ; WX 1085 ; N uni04A6 ; B -24 -165 1099 669 ;
-C -1 ; WX 667 ; N uni04AA ; B 32 -194 677 685 ;
-C -1 ; WX 444 ; N uni04AB ; B -5 -194 392 462 ;
-C -1 ; WX 611 ; N uni04AC ; B 50 -167 650 669 ;
-C -1 ; WX 494 ; N uni04AD ; B 36 -122 531 461 ;
-C -1 ; WX 611 ; N uni04AE ; B 73 0 659 669 ;
-C -1 ; WX 611 ; N uni04AF ; B 13 -220 599 449 ;
-C -1 ; WX 611 ; N uni04B0 ; B 71 0 659 669 ;
-C -1 ; WX 611 ; N uni04B1 ; B 10 -220 599 449 ;
-C -1 ; WX 667 ; N uni04B2 ; B -24 -167 694 669 ;
-C -1 ; WX 500 ; N uni04B3 ; B -46 -122 469 462 ;
-C -1 ; WX 823 ; N uni04B6 ; B 104 -167 844 669 ;
-C -1 ; WX 556 ; N uni04B7 ; B 34 -122 492 462 ;
-C -1 ; WX 823 ; N uni04BA ; B 104 0 844 669 ;
-C -1 ; WX 556 ; N uni04BB ; B 34 -9 492 462 ;
-C -1 ; WX 389 ; N uni04C0 ; B -24 0 414 669 ;
-C -1 ; WX 1107 ; N uni04C1 ; B -24 0 1132 871 ;
-C -1 ; WX 1051 ; N uni04C2 ; B 3 -13 999 664 ;
-C -1 ; WX 667 ; N uni04D0 ; B -67 0 593 888 ;
-C -1 ; WX 500 ; N uni04D1 ; B -21 -14 470 678 ;
-C -1 ; WX 667 ; N uni04D2 ; B -67 0 593 862 ;
-C -1 ; WX 500 ; N uni04D3 ; B -21 -14 471 655 ;
-C -1 ; WX 944 ; N uni04D4 ; B -64 0 918 669 ;
-C -1 ; WX 722 ; N uni04D5 ; B -5 -13 673 462 ;
-C -1 ; WX 667 ; N uni04D6 ; B -24 0 656 881 ;
-C -1 ; WX 444 ; N uni04D7 ; B 5 -13 483 674 ;
-C -1 ; WX 620 ; N uni04D8 ; B 5 -13 584 722 ;
-C -1 ; WX 444 ; N afii10846 ; B 5 -13 398 462 ;
-C -1 ; WX 620 ; N uni04DA ; B 5 -13 593 892 ;
-C -1 ; WX 444 ; N uni04DB ; B 5 -13 466 632 ;
-C -1 ; WX 1107 ; N uni04DC ; B -24 0 1132 839 ;
-C -1 ; WX 1051 ; N uni04DD ; B 3 -13 999 632 ;
-C -1 ; WX 657 ; N uni04DE ; B -18 -19 616 842 ;
-C -1 ; WX 439 ; N uni04DF ; B -12 -14 455 623 ;
-C -1 ; WX 870 ; N uni04E2 ; B -24 0 891 779 ;
-C -1 ; WX 556 ; N uni04E3 ; B 15 -9 505 572 ;
-C -1 ; WX 870 ; N uni04E4 ; B -24 0 891 839 ;
-C -1 ; WX 556 ; N uni04E5 ; B 15 -9 513 632 ;
-C -1 ; WX 722 ; N uni04E6 ; B 27 -18 691 839 ;
-C -1 ; WX 500 ; N uni04E7 ; B -3 -13 484 632 ;
-C -1 ; WX 722 ; N uni04E8 ; B 27 -18 691 685 ;
-C -1 ; WX 500 ; N uni04E9 ; B -3 -13 441 462 ;
-C -1 ; WX 722 ; N uni04EA ; B 27 -18 691 835 ;
-C -1 ; WX 500 ; N uni04EB ; B -3 -13 479 612 ;
-C -1 ; WX 732 ; N uni04EC ; B -8 -19 701 869 ;
-C -1 ; WX 451 ; N uni04ED ; B -5 -13 455 632 ;
-C -1 ; WX 766 ; N uni04EE ; B 6 -14 793 779 ;
-C -1 ; WX 444 ; N uni04EF ; B -94 -205 409 582 ;
-C -1 ; WX 766 ; N uni04F0 ; B 6 -14 793 839 ;
-C -1 ; WX 444 ; N uni04F1 ; B -94 -205 415 632 ;
-C -1 ; WX 766 ; N uni04F2 ; B 6 -14 793 890 ;
-C -1 ; WX 444 ; N uni04F3 ; B -94 -205 459 683 ;
-C -1 ; WX 823 ; N uni04F4 ; B 104 0 844 839 ;
-C -1 ; WX 556 ; N uni04F5 ; B 34 -9 513 632 ;
-C -1 ; WX 1060 ; N uni04F8 ; B -24 0 1081 839 ;
-C -1 ; WX 744 ; N uni04F9 ; B 14 -13 680 632 ;
-C -1 ; WX 389 ; N uniF6C4 ; B 0 -13 440 624 ;
-C -1 ; WX 500 ; N uniF6C5 ; B -4 -14 556 690 ;
-C -1 ; WX 500 ; N uniF6C6 ; B -68 -231 471 462 ;
-C -1 ; WX 556 ; N uniF6C7 ; B 15 -9 510 624 ;
-C -1 ; WX 806 ; N uniF6C8 ; B 15 -9 770 624 ;
-C -1 ; WX 667 ; N Ccircumflex ; B 32 -18 677 893 ;
-C -1 ; WX 444 ; N ccircumflex ; B -5 -13 439 686 ;
-C -1 ; WX 667 ; N Cdotaccent ; B 32 -18 677 849 ;
-C -1 ; WX 444 ; N cdotaccent ; B -5 -13 392 642 ;
-C -1 ; WX 667 ; N Ebreve ; B -24 0 656 881 ;
-C -1 ; WX 444 ; N ebreve ; B 5 -13 483 674 ;
-C -1 ; WX 722 ; N Gcircumflex ; B 21 -18 706 893 ;
-C -1 ; WX 500 ; N gcircumflex ; B -52 -203 478 686 ;
-C -1 ; WX 722 ; N Gdotaccent ; B 21 -18 706 849 ;
-C -1 ; WX 500 ; N gdotaccent ; B -52 -203 478 642 ;
-C -1 ; WX 778 ; N Hcircumflex ; B -24 0 799 893 ;
-C -1 ; WX 556 ; N hcircumflex ; B -13 -9 498 923 ;
-C -1 ; WX 778 ; N Hbar ; B -24 0 799 669 ;
-C -1 ; WX 556 ; N hbar ; B -13 -9 498 699 ;
-C -1 ; WX 389 ; N Itilde ; B -24 0 495 838 ;
-C -1 ; WX 278 ; N itilde ; B 2 -9 389 631 ;
-C -1 ; WX 389 ; N Ibreve ; B -24 0 502 881 ;
-C -1 ; WX 278 ; N ibreve ; B 2 -9 395 674 ;
-C -1 ; WX 826 ; N IJ ; B -24 -99 858 669 ;
-C -1 ; WX 525 ; N ij ; B 2 -207 519 685 ;
-C -1 ; WX 500 ; N Jcircumflex ; B -46 -99 524 893 ;
-C -1 ; WX 278 ; N jcircumflex ; B -189 -207 343 769 ;
-C -1 ; WX 534 ; N kgreenlandic ; B -6 0 514 470 ;
-C -1 ; WX 611 ; N Ldot ; B -24 0 588 669 ;
-C -1 ; WX 528 ; N ldot ; B 2 -9 477 699 ;
-C -1 ; WX 556 ; N napostrophe ; B -6 -9 493 786 ;
-C -1 ; WX 722 ; N Obreve ; B 27 -18 691 881 ;
-C -1 ; WX 500 ; N obreve ; B -3 -13 501 674 ;
-C -1 ; WX 556 ; N Scircumflex ; B 2 -18 553 893 ;
-C -1 ; WX 389 ; N scircumflex ; B -19 -13 405 686 ;
-C -1 ; WX 611 ; N Tbar ; B 50 0 650 669 ;
-C -1 ; WX 278 ; N tbar ; B -15 -9 281 594 ;
-C -1 ; WX 722 ; N Utilde ; B 67 -18 744 838 ;
-C -1 ; WX 556 ; N utilde ; B 15 -9 523 631 ;
-C -1 ; WX 722 ; N Ubreve ; B 67 -18 744 881 ;
-C -1 ; WX 556 ; N ubreve ; B 15 -9 530 674 ;
-C -1 ; WX 889 ; N Wcircumflex ; B 65 -18 940 893 ;
-C -1 ; WX 667 ; N wcircumflex ; B 16 -13 614 686 ;
-C -1 ; WX 611 ; N Ycircumflex ; B 73 0 659 893 ;
-C -1 ; WX 444 ; N ycircumflex ; B -94 -205 392 686 ;
-C -1 ; WX 333 ; N longs ; B -169 -205 446 698 ;
-C -1 ; WX 981 ; N afii61352 ; B 14 -25 1010 681 ;
-C -1 ; WX 752 ; N infinity ; B 14 42 734 456 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 986
-KPX quoteright y -18
-KPX quoteright w -23
-KPX quoteright v -23
-KPX quoteright t -19
-KPX quoteright s -26
-KPX quoteright r -26
-KPX quoteright period -59
-KPX quoteright o -50
-KPX quoteright d -50
-KPX quoteright comma -57
-KPX quoteright Aring -94
-KPX quoteright Adieresis -94
-KPX quoteright Aacute -94
-KPX quoteright AE -116
-KPX quoteright A -94
-KPX comma quoteright -23
-KPX comma quotedblright -1
-KPX comma one -26
-KPX hyphen Y -69
-KPX hyphen W -59
-KPX hyphen V -62
-KPX hyphen T -59
-KPX hyphen Aring -13
-KPX hyphen Adieresis -13
-KPX hyphen Aacute -13
-KPX hyphen AE -22
-KPX hyphen A -13
-KPX period quoteright -27
-KPX period quotedblright -5
-KPX period one -32
-KPX zero seven -12
-KPX zero one -50
-KPX zero four -1
-KPX one zero -48
-KPX one two -32
-KPX one three -43
-KPX one six -62
-KPX one seven -65
-KPX one period -39
-KPX one one -48
-KPX one nine -40
-KPX one four -75
-KPX one five -45
-KPX one eight -56
-KPX one comma -38
-KPX two seven -27
-KPX two one -48
-KPX two four -8
-KPX three seven -27
-KPX three one -67
-KPX three four -15
-KPX four seven -21
-KPX four one -50
-KPX four four 1
-KPX five seven -37
-KPX five one -56
-KPX five four -13
-KPX six seven -32
-KPX six one -52
-KPX six four 2
-KPX seven two -30
-KPX seven three -42
-KPX seven six -60
-KPX seven seven -27
-KPX seven period -81
-KPX seven one -43
-KPX seven four -79
-KPX seven five -60
-KPX seven eight -46
-KPX seven comma -80
-KPX seven colon -90
-KPX eight seven -13
-KPX eight one -52
-KPX eight four -4
-KPX nine seven -12
-KPX nine one -67
-KPX nine four -18
-KPX A y -67
-KPX A w -56
-KPX A v -51
-KPX A u -18
-KPX A t -4
-KPX A quoteright -101
-KPX A quotedblright -78
-KPX A q -18
-KPX A period 1
-KPX A o -23
-KPX A hyphen -23
-KPX A guilsinglleft -68
-KPX A guillemotleft -58
-KPX A g -20
-KPX A e -25
-KPX A d -5
-KPX A ccedilla -29
-KPX A c -20
-KPX A b -1
-KPX A a -5
-KPX A Y -44
-KPX A W -107
-KPX A V -110
-KPX A Ugrave -61
-KPX A Udieresis -61
-KPX A Ucircumflex -61
-KPX A Uacute -61
-KPX A U -61
-KPX A T -33
-KPX A Q -54
-KPX A Odieresis -53
-KPX A O -53
-KPX A G -59
-KPX A Ccedilla -63
-KPX A C -61
-KPX B Y -50
-KPX B W -46
-KPX B V -46
-KPX B Oslash -23
-KPX B Ograve -22
-KPX B Odieresis -22
-KPX B Ocircumflex -22
-KPX B Oacute -22
-KPX B OE -20
-KPX B O -22
-KPX B Atilde -34
-KPX B Aring -34
-KPX B Adieresis -34
-KPX B Acircumflex -34
-KPX B Aacute -34
-KPX B AE -40
-KPX B A -34
-KPX C Odieresis -25
-KPX C Oacute -25
-KPX C O -25
-KPX C K -28
-KPX C H -26
-KPX C Aring -24
-KPX C Adieresis -24
-KPX C Aacute -24
-KPX C AE -31
-KPX C A -24
-KPX D Y -64
-KPX D X -64
-KPX D W -58
-KPX D V -60
-KPX D T -27
-KPX D J -67
-KPX D Atilde -54
-KPX D Aring -54
-KPX D Agrave -54
-KPX D Adieresis -54
-KPX D Acircumflex -54
-KPX D Aacute -54
-KPX D A -54
-KPX F u -42
-KPX F r -38
-KPX F period -98
-KPX F oslash -79
-KPX F oe -86
-KPX F odieresis -45
-KPX F oacute -82
-KPX F o -81
-KPX F j -34
-KPX F i -29
-KPX F hyphen -54
-KPX F eacute -86
-KPX F e -86
-KPX F comma -96
-KPX F aring -75
-KPX F ae -83
-KPX F adieresis -48
-KPX F aacute -75
-KPX F a -75
-KPX F Odieresis -48
-KPX F O -48
-KPX F J -88
-KPX F Atilde -101
-KPX F Aring -101
-KPX F Agrave -101
-KPX F Adieresis -101
-KPX F Acircumflex -101
-KPX F Aacute -101
-KPX F A -101
-KPX G Y -31
-KPX G W -27
-KPX G V -27
-KPX G T -42
-KPX G Atilde -14
-KPX G Aring -14
-KPX G Agrave -14
-KPX G Adieresis -14
-KPX G Acircumflex -14
-KPX G Aacute -14
-KPX G AE -20
-KPX G A -14
-KPX J Aring -39
-KPX J Adieresis -39
-KPX J AE -42
-KPX J A -39
-KPX K y -68
-KPX K udieresis -8
-KPX K u -8
-KPX K odieresis -13
-KPX K oacute -13
-KPX K o -13
-KPX K hyphen -30
-KPX K e -16
-KPX K aring 3
-KPX K ae -4
-KPX K adieresis 3
-KPX K a 3
-KPX K S -1
-KPX K Odieresis -43
-KPX K Oacute -43
-KPX K OE -42
-KPX K O -43
-KPX K G -46
-KPX K C -51
-KPX L y -23
-KPX L udieresis 5
-KPX L u 5
-KPX L quoteright -67
-KPX L quotedblright -45
-KPX L hyphen 41
-KPX L Y -41
-KPX L W -74
-KPX L V -77
-KPX L Udieresis -17
-KPX L U -17
-KPX L T -30
-KPX L S 1
-KPX L Otilde 4
-KPX L Ograve 4
-KPX L Odieresis 4
-KPX L Ocircumflex 4
-KPX L Oacute 4
-KPX L O 4
-KPX L G 4
-KPX L Aring 28
-KPX L Adieresis 28
-KPX L Aacute 28
-KPX L AE 25
-KPX L A 28
-KPX N udieresis -33
-KPX N u -33
-KPX N period -26
-KPX N oslash -32
-KPX N odieresis -34
-KPX N oacute -34
-KPX N o -32
-KPX N eacute -38
-KPX N e -37
-KPX N comma -24
-KPX N aring -27
-KPX N ae -34
-KPX N adieresis -27
-KPX N aacute -27
-KPX N a -25
-KPX N Odieresis -32
-KPX N Oacute -32
-KPX N O -32
-KPX N G -26
-KPX N Ccedilla -30
-KPX N C -32
-KPX N Aring -39
-KPX N Adieresis -39
-KPX N Aacute -39
-KPX N AE -42
-KPX N A -39
-KPX O Y -56
-KPX O X -63
-KPX O W -52
-KPX O V -52
-KPX O T -18
-KPX O Aring -57
-KPX O Adieresis -57
-KPX O Aacute -57
-KPX O AE -67
-KPX O A -57
-KPX P period -109
-KPX P oslash -47
-KPX P oe -57
-KPX P odieresis -35
-KPX P oacute -52
-KPX P o -52
-KPX P hyphen -54
-KPX P eacute -57
-KPX P e -57
-KPX P comma -107
-KPX P aring -50
-KPX P ae -58
-KPX P adieresis -38
-KPX P aacute -50
-KPX P a -50
-KPX P J -105
-KPX P Aring -89
-KPX P Adieresis -89
-KPX P Aacute -89
-KPX P AE -104
-KPX P A -89
-KPX R y -12
-KPX R udieresis -13
-KPX R uacute -13
-KPX R u -13
-KPX R oe -23
-KPX R odieresis -18
-KPX R oacute -18
-KPX R o -18
-KPX R hyphen -30
-KPX R eacute -21
-KPX R e -21
-KPX R aring -1
-KPX R ae -9
-KPX R adieresis -1
-KPX R aacute -1
-KPX R a -1
-KPX R Y -40
-KPX R W -46
-KPX R V -46
-KPX R Udieresis -44
-KPX R U -44
-KPX R T -24
-KPX R Odieresis -34
-KPX R Oacute -34
-KPX R OE -32
-KPX R O -34
-KPX R G -28
-KPX R Ccedilla -32
-KPX R C -33
-KPX S t -6
-KPX S Y -24
-KPX S W -20
-KPX S V -20
-KPX S T -34
-KPX S Aring -11
-KPX S Adieresis -11
-KPX S Aacute -11
-KPX S AE -17
-KPX S A -11
-KPX T y -86
-KPX T w -89
-KPX T v -89
-KPX T u -91
-KPX T semicolon -98
-KPX T s -78
-KPX T r -76
-KPX T period -79
-KPX T oslash -90
-KPX T o -90
-KPX T j -27
-KPX T i -19
-KPX T hyphen -74
-KPX T guilsinglleft -120
-KPX T guillemotleft -110
-KPX T g -95
-KPX T e -94
-KPX T comma -77
-KPX T colon -98
-KPX T c -89
-KPX T ae -91
-KPX T a -83
-KPX T Y 11
-KPX T W 15
-KPX T V 15
-KPX T S -16
-KPX T Otilde -22
-KPX T Oslash -22
-KPX T Ograve -22
-KPX T Odieresis -22
-KPX T Ocircumflex -22
-KPX T Oacute -22
-KPX T OE -18
-KPX T O -22
-KPX T J -63
-KPX T G -9
-KPX T C -15
-KPX T Atilde -52
-KPX T Aring -52
-KPX T Agrave -52
-KPX T Adieresis -52
-KPX T Acircumflex -52
-KPX T Aacute -52
-KPX T AE -54
-KPX T A -52
-KPX U r -32
-KPX U period -41
-KPX U p -30
-KPX U n -39
-KPX U m -35
-KPX U comma -40
-KPX U Atilde -65
-KPX U Aring -65
-KPX U Adieresis -65
-KPX U Acircumflex -65
-KPX U Aacute -65
-KPX U AE -71
-KPX U A -65
-KPX V y -34
-KPX V u -47
-KPX V semicolon -96
-KPX V r -44
-KPX V period -97
-KPX V oslash -81
-KPX V o -83
-KPX V i -12
-KPX V hyphen -62
-KPX V guilsinglleft -109
-KPX V guillemotleft -99
-KPX V g -83
-KPX V e -87
-KPX V comma -96
-KPX V colon -96
-KPX V ae -84
-KPX V a -76
-KPX V T 7
-KPX V S -25
-KPX V Otilde -64
-KPX V Oslash -64
-KPX V Ograve -64
-KPX V Odieresis -64
-KPX V Ocircumflex -64
-KPX V Oacute -64
-KPX V O -64
-KPX V G -53
-KPX V C -60
-KPX V Atilde -100
-KPX V Aring -100
-KPX V Agrave -100
-KPX V Adieresis -100
-KPX V Acircumflex -100
-KPX V Aacute -100
-KPX V AE -111
-KPX V A -100
-KPX W y -25
-KPX W u -38
-KPX W semicolon -79
-KPX W r -34
-KPX W period -64
-KPX W oslash -57
-KPX W o -58
-KPX W i -11
-KPX W hyphen -37
-KPX W guilsinglleft -84
-KPX W guillemotleft -74
-KPX W g -63
-KPX W e -62
-KPX W comma -62
-KPX W colon -78
-KPX W ae -60
-KPX W a -51
-KPX W T 8
-KPX W S -24
-KPX W Otilde -47
-KPX W Oslash -48
-KPX W Ograve -47
-KPX W Odieresis -47
-KPX W Ocircumflex -47
-KPX W Oacute -47
-KPX W O -47
-KPX W G -41
-KPX W C -46
-KPX W Atilde -83
-KPX W Aring -83
-KPX W Agrave -83
-KPX W Adieresis -83
-KPX W Acircumflex -83
-KPX W Aacute -83
-KPX W AE -87
-KPX W A -83
-KPX X y -81
-KPX X u -21
-KPX X o -26
-KPX X hyphen -46
-KPX X e -29
-KPX X a -9
-KPX X Q -58
-KPX X Odieresis -56
-KPX X O -56
-KPX X C -58
-KPX Y v -54
-KPX Y u -59
-KPX Y semicolon -91
-KPX Y period -69
-KPX Y p -54
-KPX Y oslash -75
-KPX Y o -76
-KPX Y i -12
-KPX Y hyphen -63
-KPX Y guilsinglleft -107
-KPX Y guillemotleft -97
-KPX Y g -81
-KPX Y e -80
-KPX Y comma -67
-KPX Y colon -91
-KPX Y ae -77
-KPX Y a -69
-KPX Y T 7
-KPX Y S -25
-KPX Y Otilde -61
-KPX Y Oslash -61
-KPX Y Ograve -61
-KPX Y Odieresis -61
-KPX Y Ocircumflex -61
-KPX Y Oacute -61
-KPX Y O -61
-KPX Y G -54
-KPX Y C -59
-KPX Y Atilde -45
-KPX Y Aring -45
-KPX Y Agrave -45
-KPX Y Adieresis -45
-KPX Y Acircumflex -45
-KPX Y Aacute -45
-KPX Y AE -47
-KPX Y A -45
-KPX Z y -39
-KPX Z v -29
-KPX quoteleft Y -7
-KPX quoteleft W -3
-KPX quoteleft V -3
-KPX quoteleft T -18
-KPX quoteleft Aring -83
-KPX quoteleft Adieresis -83
-KPX quoteleft Aacute -83
-KPX quoteleft AE -105
-KPX quoteleft A -83
-KPX a y -3
-KPX a w -5
-KPX a v -5
-KPX a quoteright -22
-KPX a j -2
-KPX b y -17
-KPX b w -12
-KPX b v -12
-KPX c k -16
-KPX c h -20
-KPX e y -6
-KPX e x -15
-KPX e w -3
-KPX e v -3
-KPX e t -3
-KPX e quoteright -12
-KPX f t 9
-KPX f s -14
-KPX f quoteright 12
-KPX f oslash -29
-KPX f oe -35
-KPX f odieresis 20
-KPX f oacute -31
-KPX f o -30
-KPX f l 43
-KPX f j 12
-KPX f i 20
-KPX f f 2
-KPX f eacute -36
-KPX f e -35
-KPX f aring -20
-KPX f ae -32
-KPX f adieresis 17
-KPX f aacute -24
-KPX f a -23
-KPX g r 3
-KPX g odieresis -27
-KPX g oacute -27
-KPX g l -21
-KPX g eacute -32
-KPX g e -32
-KPX g aring -25
-KPX g ae -34
-KPX g adieresis -25
-KPX g a -25
-KPX h y -20
-KPX h quoteright -32
-KPX i j -5
-KPX i T -20
-KPX k udieresis 2
-KPX k u 2
-KPX k s 1
-KPX k period 17
-KPX k odieresis 1
-KPX k oacute 1
-KPX k o 1
-KPX k hyphen 1
-KPX k g -14
-KPX k eacute -2
-KPX k e -2
-KPX k comma 19
-KPX k aring 10
-KPX k ae 2
-KPX k adieresis 10
-KPX k aacute 10
-KPX k a 10
-KPX l y -8
-KPX l v -12
-KPX m y -16
-KPX m w -16
-KPX m v -16
-KPX m p -1
-KPX n y -20
-KPX n w -20
-KPX n v -20
-KPX n quoteright -32
-KPX n p -4
-KPX n T -59
-KPX o y -29
-KPX o x -26
-KPX o w -21
-KPX o v -21
-KPX o t -2
-KPX o quoteright -22
-KPX o T -75
-KPX p y -13
-KPX p t -2
-KPX q u -5
-KPX q c -6
-KPX r z 10
-KPX r y 20
-KPX r x 7
-KPX r w 20
-KPX r v 20
-KPX r u 11
-KPX r t 12
-KPX r semicolon -30
-KPX r s 1
-KPX r r 14
-KPX r q -19
-KPX r period -69
-KPX r p 16
-KPX r oslash -12
-KPX r ograve -15
-KPX r oe -19
-KPX r odieresis -15
-KPX r ocircumflex -15
-KPX r oacute -15
-KPX r o -15
-KPX r n 6
-KPX r m 10
-KPX r l -12
-KPX r k -11
-KPX r j 12
-KPX r i 17
-KPX r hyphen -13
-KPX r h -16
-KPX r g -4
-KPX r f 8
-KPX r egrave -20
-KPX r ecircumflex -20
-KPX r eacute -20
-KPX r e -20
-KPX r d -14
-KPX r comma -67
-KPX r colon -30
-KPX r ccedilla -8
-KPX r c -15
-KPX r aring -13
-KPX r agrave -13
-KPX r ae -22
-KPX r adieresis -13
-KPX r acircumflex -13
-KPX r aacute -13
-KPX r a -13
-KPX s t -6
-KPX s quoteright -22
-KPX t semicolon -23
-KPX t quoteright -19
-KPX t odieresis 1
-KPX t oacute 1
-KPX t o 1
-KPX t h -5
-KPX t eacute -2
-KPX t e -2
-KPX t colon -22
-KPX t aring 10
-KPX t ae 2
-KPX t adieresis 10
-KPX t aacute 10
-KPX t a 10
-KPX t S -11
-KPX u quoteright -33
-KPX v semicolon -51
-KPX v s -19
-KPX v period -51
-KPX v oslash -22
-KPX v ograve -24
-KPX v odieresis -24
-KPX v oacute -24
-KPX v o -24
-KPX v l -24
-KPX v hyphen -1
-KPX v g -20
-KPX v egrave -28
-KPX v ecircumflex -28
-KPX v eacute -28
-KPX v e -28
-KPX v comma -51
-KPX v colon -51
-KPX v c -24
-KPX v atilde -20
-KPX v aring -20
-KPX v agrave -20
-KPX v ae -28
-KPX v adieresis -20
-KPX v acircumflex -20
-KPX v aacute -20
-KPX v a -20
-KPX w semicolon -56
-KPX w s -24
-KPX w period -53
-KPX w oslash -28
-KPX w ograve -30
-KPX w odieresis -30
-KPX w oacute -30
-KPX w o -30
-KPX w l -28
-KPX w hyphen -7
-KPX w g -26
-KPX w egrave -34
-KPX w ecircumflex -34
-KPX w eacute -34
-KPX w e -34
-KPX w comma -53
-KPX w colon -56
-KPX w c -30
-KPX w atilde -24
-KPX w aring -24
-KPX w agrave -24
-KPX w ae -32
-KPX w adieresis -24
-KPX w acircumflex -24
-KPX w aacute -24
-KPX w a -24
-KPX x q -12
-KPX x o -11
-KPX x eacute -14
-KPX x e -14
-KPX x c -10
-KPX x a -1
-KPX y semicolon -44
-KPX y s -13
-KPX y period -26
-KPX y oslash -17
-KPX y ograve -19
-KPX y odieresis -19
-KPX y oacute -19
-KPX y o -17
-KPX y l -16
-KPX y hyphen 2
-KPX y g -23
-KPX y egrave -23
-KPX y ecircumflex -23
-KPX y eacute -23
-KPX y e -22
-KPX y comma -25
-KPX y colon -43
-KPX y c -17
-KPX y atilde -12
-KPX y aring -12
-KPX y agrave -12
-KPX y ae -19
-KPX y adieresis -12
-KPX y acircumflex -12
-KPX y aacute -12
-KPX y a -11
-KPX quotedblleft W 3
-KPX quotedblleft V 3
-KPX quotedblleft T -11
-KPX quotedblleft Aring -76
-KPX quotedblleft Adieresis -76
-KPX quotedblleft Aacute -76
-KPX quotedblleft AE -98
-KPX quotedblleft A -76
-KPX guilsinglright Y -93
-KPX guilsinglright W -85
-KPX guilsinglright V -89
-KPX guilsinglright T -86
-KPX guilsinglright Aring -40
-KPX guilsinglright Adieresis -40
-KPX guilsinglright Aacute -40
-KPX guilsinglright AE -49
-KPX guilsinglright A -40
-KPX quotedblbase Y -48
-KPX quotedblbase W -74
-KPX quotedblbase V -79
-KPX quotedblbase T -37
-KPX quotedblbase AE 19
-KPX quotedblbase A 24
-KPX quotedblright Y 2
-KPX quotedblright W 6
-KPX quotedblright V 6
-KPX quotedblright T -1
-KPX quotedblright Aring -72
-KPX quotedblright Adieresis -72
-KPX quotedblright Aacute -72
-KPX quotedblright AE -94
-KPX quotedblright A -72
-KPX guillemotright Y -83
-KPX guillemotright W -75
-KPX guillemotright V -79
-KPX guillemotright T -76
-KPX guillemotright Aring -30
-KPX guillemotright Adieresis -30
-KPX guillemotright Aacute -30
-KPX guillemotright AE -39
-KPX guillemotright A -30
-KPX Oslash A -57
-KPX ae y -8
-KPX ae w -5
-KPX ae v -5
-KPX Adieresis y -67
-KPX Adieresis w -56
-KPX Adieresis v -51
-KPX Adieresis u -18
-KPX Adieresis t -4
-KPX Adieresis quoteright -101
-KPX Adieresis quotedblright -78
-KPX Adieresis q -18
-KPX Adieresis period 1
-KPX Adieresis o -23
-KPX Adieresis hyphen -23
-KPX Adieresis guilsinglleft -68
-KPX Adieresis guillemotleft -58
-KPX Adieresis g -20
-KPX Adieresis d -5
-KPX Adieresis c -20
-KPX Adieresis b -1
-KPX Adieresis a -5
-KPX Adieresis Y -44
-KPX Adieresis W -107
-KPX Adieresis V -110
-KPX Adieresis U -61
-KPX Adieresis T -33
-KPX Adieresis Q -54
-KPX Adieresis O -53
-KPX Adieresis G -59
-KPX Adieresis C -61
-KPX Aacute y -67
-KPX Aacute w -56
-KPX Aacute v -51
-KPX Aacute u -18
-KPX Aacute t -4
-KPX Aacute quoteright -101
-KPX Aacute q -18
-KPX Aacute period 1
-KPX Aacute o -23
-KPX Aacute hyphen -23
-KPX Aacute guilsinglleft -68
-KPX Aacute guillemotleft -58
-KPX Aacute g -20
-KPX Aacute e -25
-KPX Aacute d -5
-KPX Aacute c -20
-KPX Aacute b -1
-KPX Aacute a -5
-KPX Aacute Y -44
-KPX Aacute W -107
-KPX Aacute V -110
-KPX Aacute U -61
-KPX Aacute T -33
-KPX Aacute Q -54
-KPX Aacute O -53
-KPX Aacute G -59
-KPX Aacute C -61
-KPX Agrave period 1
-KPX Agrave Y -44
-KPX Agrave W -107
-KPX Agrave V -110
-KPX Agrave U -61
-KPX Agrave T -33
-KPX Agrave Q -54
-KPX Agrave O -53
-KPX Agrave G -59
-KPX Agrave C -61
-KPX Acircumflex period 1
-KPX Acircumflex Y -44
-KPX Acircumflex W -107
-KPX Acircumflex V -110
-KPX Acircumflex U -61
-KPX Acircumflex T -33
-KPX Acircumflex Q -54
-KPX Acircumflex O -53
-KPX Acircumflex G -59
-KPX Acircumflex C -61
-KPX Atilde period 1
-KPX Atilde Y -44
-KPX Atilde W -107
-KPX Atilde V -110
-KPX Atilde U -61
-KPX Atilde T -33
-KPX Atilde Q -54
-KPX Atilde O -53
-KPX Atilde G -59
-KPX Atilde C -61
-KPX Aring y -67
-KPX Aring w -56
-KPX Aring v -51
-KPX Aring u -18
-KPX Aring t -4
-KPX Aring quoteright -101
-KPX Aring quotedblright -78
-KPX Aring q -18
-KPX Aring period 1
-KPX Aring o -23
-KPX Aring hyphen -23
-KPX Aring guilsinglleft -68
-KPX Aring guillemotleft -58
-KPX Aring g -20
-KPX Aring e -25
-KPX Aring d -5
-KPX Aring c -20
-KPX Aring b -1
-KPX Aring a -5
-KPX Aring Y -44
-KPX Aring W -107
-KPX Aring V -110
-KPX Aring U -61
-KPX Aring T -33
-KPX Aring Q -54
-KPX Aring O -53
-KPX Aring G -59
-KPX Aring C -61
-KPX Ccedilla A -30
-KPX Odieresis Y -56
-KPX Odieresis X -63
-KPX Odieresis W -52
-KPX Odieresis V -52
-KPX Odieresis T -18
-KPX Odieresis A -57
-KPX Oacute Y -56
-KPX Oacute W -52
-KPX Oacute V -52
-KPX Oacute T -18
-KPX Oacute A -57
-KPX Ograve Y -56
-KPX Ograve V -52
-KPX Ograve T -18
-KPX Ocircumflex Y -56
-KPX Ocircumflex V -52
-KPX Ocircumflex T -18
-KPX Otilde Y -56
-KPX Otilde V -52
-KPX Otilde T -18
-KPX Udieresis r -32
-KPX Udieresis period -41
-KPX Udieresis p -30
-KPX Udieresis n -39
-KPX Udieresis m -35
-KPX Udieresis comma -40
-KPX Udieresis b 1
-KPX Udieresis A -65
-KPX Uacute r -32
-KPX Uacute period -41
-KPX Uacute p -30
-KPX Uacute n -39
-KPX Uacute m -35
-KPX Uacute comma -40
-KPX Uacute A -65
-KPX Ugrave A -65
-KPX Ucircumflex A -65
-KPX adieresis y -3
-KPX adieresis w -5
-KPX adieresis v -5
-KPX aacute y -3
-KPX aacute w -5
-KPX aacute v -5
-KPX agrave y -3
-KPX agrave w -5
-KPX agrave v -5
-KPX aring y -3
-KPX aring w -5
-KPX aring v -5
-KPX eacute y -6
-KPX eacute w -3
-KPX eacute v -3
-KPX ecircumflex y -6
-KPX ecircumflex w -3
-KPX ecircumflex v -3
-KPX odieresis y -29
-KPX odieresis x -26
-KPX odieresis w -21
-KPX odieresis v -21
-KPX odieresis t -4
-KPX oacute y -29
-KPX oacute w -21
-KPX oacute v -21
-KPX ograve y -29
-KPX ograve w -21
-KPX ograve v -21
-KPX ocircumflex t -4
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-roman-no-9-l/n021024l.pfb b/src/fonts/nimbus-roman-no-9-l/n021024l.pfb
deleted file mode 100644
index f24f480..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021024l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-roman-no-9-l/n021024l.pfm b/src/fonts/nimbus-roman-no-9-l/n021024l.pfm
deleted file mode 100644
index 0271aa5..0000000
--- a/src/fonts/nimbus-roman-no-9-l/n021024l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/LICENSE b/src/fonts/nimbus-sans-l/LICENSE
deleted file mode 100644
index 2244313..0000000
--- a/src/fonts/nimbus-sans-l/LICENSE
+++ /dev/null
@@ -1,416 +0,0 @@
-The LaTeX Project Public License
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-LPPL Version 1.3c 2008-05-04
-
-Copyright 1999 2002-2008 LaTeX3 Project
- Everyone is allowed to distribute verbatim copies of this
- license document, but modification of it is not allowed.
-
-
-PREAMBLE
-========
-
-The LaTeX Project Public License (LPPL) is the primary license under
-which the LaTeX kernel and the base LaTeX packages are distributed.
-
-You may use this license for any work of which you hold the copyright
-and which you wish to distribute. This license may be particularly
-suitable if your work is TeX-related (such as a LaTeX package), but
-it is written in such a way that you can use it even if your work is
-unrelated to TeX.
-
-The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE',
-below, gives instructions, examples, and recommendations for authors
-who are considering distributing their works under this license.
-
-This license gives conditions under which a work may be distributed
-and modified, as well as conditions under which modified versions of
-that work may be distributed.
-
-We, the LaTeX3 Project, believe that the conditions below give you
-the freedom to make and distribute modified versions of your work
-that conform with whatever technical specifications you wish while
-maintaining the availability, integrity, and reliability of
-that work. If you do not see how to achieve your goal while
-meeting these conditions, then read the document `cfgguide.tex'
-and `modguide.tex' in the base LaTeX distribution for suggestions.
-
-
-DEFINITIONS
-===========
-
-In this license document the following terms are used:
-
- `Work'
- Any work being distributed under this License.
-
- `Derived Work'
- Any work that under any applicable law is derived from the Work.
-
- `Modification'
- Any procedure that produces a Derived Work under any applicable
- law -- for example, the production of a file containing an
- original file associated with the Work or a significant portion of
- such a file, either verbatim or with modifications and/or
- translated into another language.
-
- `Modify'
- To apply any procedure that produces a Derived Work under any
- applicable law.
-
- `Distribution'
- Making copies of the Work available from one person to another, in
- whole or in part. Distribution includes (but is not limited to)
- making any electronic components of the Work accessible by
- file transfer protocols such as FTP or HTTP or by shared file
- systems such as Sun's Network File System (NFS).
-
- `Compiled Work'
- A version of the Work that has been processed into a form where it
- is directly usable on a computer system. This processing may
- include using installation facilities provided by the Work,
- transformations of the Work, copying of components of the Work, or
- other activities. Note that modification of any installation
- facilities provided by the Work constitutes modification of the Work.
-
- `Current Maintainer'
- A person or persons nominated as such within the Work. If there is
- no such explicit nomination then it is the `Copyright Holder' under
- any applicable law.
-
- `Base Interpreter'
- A program or process that is normally needed for running or
- interpreting a part or the whole of the Work.
-
- A Base Interpreter may depend on external components but these
- are not considered part of the Base Interpreter provided that each
- external component clearly identifies itself whenever it is used
- interactively. Unless explicitly specified when applying the
- license to the Work, the only applicable Base Interpreter is a
- `LaTeX-Format' or in the case of files belonging to the
- `LaTeX-format' a program implementing the `TeX language'.
-
-
-
-CONDITIONS ON DISTRIBUTION AND MODIFICATION
-===========================================
-
-1. Activities other than distribution and/or modification of the Work
-are not covered by this license; they are outside its scope. In
-particular, the act of running the Work is not restricted and no
-requirements are made concerning any offers of support for the Work.
-
-2. You may distribute a complete, unmodified copy of the Work as you
-received it. Distribution of only part of the Work is considered
-modification of the Work, and no right to distribute such a Derived
-Work may be assumed under the terms of this clause.
-
-3. You may distribute a Compiled Work that has been generated from a
-complete, unmodified copy of the Work as distributed under Clause 2
-above, as long as that Compiled Work is distributed in such a way that
-the recipients may install the Compiled Work on their system exactly
-as it would have been installed if they generated a Compiled Work
-directly from the Work.
-
-4. If you are the Current Maintainer of the Work, you may, without
-restriction, modify the Work, thus creating a Derived Work. You may
-also distribute the Derived Work without restriction, including
-Compiled Works generated from the Derived Work. Derived Works
-distributed in this manner by the Current Maintainer are considered to
-be updated versions of the Work.
-
-5. If you are not the Current Maintainer of the Work, you may modify
-your copy of the Work, thus creating a Derived Work based on the Work,
-and compile this Derived Work, thus creating a Compiled Work based on
-the Derived Work.
-
-6. If you are not the Current Maintainer of the Work, you may
-distribute a Derived Work provided the following conditions are met
-for every component of the Work unless that component clearly states
-in the copyright notice that it is exempt from that condition. Only
-the Current Maintainer is allowed to add such statements of exemption
-to a component of the Work.
-
- a. If a component of this Derived Work can be a direct replacement
- for a component of the Work when that component is used with the
- Base Interpreter, then, wherever this component of the Work
- identifies itself to the user when used interactively with that
- Base Interpreter, the replacement component of this Derived Work
- clearly and unambiguously identifies itself as a modified version
- of this component to the user when used interactively with that
- Base Interpreter.
-
- b. Every component of the Derived Work contains prominent notices
- detailing the nature of the changes to that component, or a
- prominent reference to another file that is distributed as part
- of the Derived Work and that contains a complete and accurate log
- of the changes.
-
- c. No information in the Derived Work implies that any persons,
- including (but not limited to) the authors of the original version
- of the Work, provide any support, including (but not limited to)
- the reporting and handling of errors, to recipients of the
- Derived Work unless those persons have stated explicitly that
- they do provide such support for the Derived Work.
-
- d. You distribute at least one of the following with the Derived Work:
-
- 1. A complete, unmodified copy of the Work;
- if your distribution of a modified component is made by
- offering access to copy the modified component from a
- designated place, then offering equivalent access to copy
- the Work from the same or some similar place meets this
- condition, even though third parties are not compelled to
- copy the Work along with the modified component;
-
- 2. Information that is sufficient to obtain a complete,
- unmodified copy of the Work.
-
-7. If you are not the Current Maintainer of the Work, you may
-distribute a Compiled Work generated from a Derived Work, as long as
-the Derived Work is distributed to all recipients of the Compiled
-Work, and as long as the conditions of Clause 6, above, are met with
-regard to the Derived Work.
-
-8. The conditions above are not intended to prohibit, and hence do not
-apply to, the modification, by any method, of any component so that it
-becomes identical to an updated version of that component of the Work as
-it is distributed by the Current Maintainer under Clause 4, above.
-
-9. Distribution of the Work or any Derived Work in an alternative
-format, where the Work or that Derived Work (in whole or in part) is
-then produced by applying some process to that format, does not relax or
-nullify any sections of this license as they pertain to the results of
-applying that process.
-
-10. a. A Derived Work may be distributed under a different license
- provided that license itself honors the conditions listed in
- Clause 6 above, in regard to the Work, though it does not have
- to honor the rest of the conditions in this license.
-
- b. If a Derived Work is distributed under a different license, that
- Derived Work must provide sufficient documentation as part of
- itself to allow each recipient of that Derived Work to honor the
- restrictions in Clause 6 above, concerning changes from the Work.
-
-11. This license places no restrictions on works that are unrelated to
-the Work, nor does this license place any restrictions on aggregating
-such works with the Work by any means.
-
-12. Nothing in this license is intended to, or may be used to, prevent
-complete compliance by all parties with all applicable laws.
-
-
-NO WARRANTY
-===========
-
-There is no warranty for the Work. Except when otherwise stated in
-writing, the Copyright Holder provides the Work `as is', without
-warranty of any kind, either expressed or implied, including, but not
-limited to, the implied warranties of merchantability and fitness for a
-particular purpose. The entire risk as to the quality and performance
-of the Work is with you. Should the Work prove defective, you assume
-the cost of all necessary servicing, repair, or correction.
-
-In no event unless required by applicable law or agreed to in writing
-will The Copyright Holder, or any author named in the components of the
-Work, or any other party who may distribute and/or modify the Work as
-permitted above, be liable to you for damages, including any general,
-special, incidental or consequential damages arising out of any use of
-the Work or out of inability to use the Work (including, but not limited
-to, loss of data, data being rendered inaccurate, or losses sustained by
-anyone as a result of any failure of the Work to operate with any other
-programs), even if the Copyright Holder or said author or said other
-party has been advised of the possibility of such damages.
-
-
-MAINTENANCE OF THE WORK
-=======================
-
-The Work has the status `author-maintained' if the Copyright Holder
-explicitly and prominently states near the primary copyright notice in
-the Work that the Work can only be maintained by the Copyright Holder
-or simply that it is `author-maintained'.
-
-The Work has the status `maintained' if there is a Current Maintainer
-who has indicated in the Work that they are willing to receive error
-reports for the Work (for example, by supplying a valid e-mail
-address). It is not required for the Current Maintainer to acknowledge
-or act upon these error reports.
-
-The Work changes from status `maintained' to `unmaintained' if there
-is no Current Maintainer, or the person stated to be Current
-Maintainer of the work cannot be reached through the indicated means
-of communication for a period of six months, and there are no other
-significant signs of active maintenance.
-
-You can become the Current Maintainer of the Work by agreement with
-any existing Current Maintainer to take over this role.
-
-If the Work is unmaintained, you can become the Current Maintainer of
-the Work through the following steps:
-
- 1. Make a reasonable attempt to trace the Current Maintainer (and
- the Copyright Holder, if the two differ) through the means of
- an Internet or similar search.
-
- 2. If this search is successful, then enquire whether the Work
- is still maintained.
-
- a. If it is being maintained, then ask the Current Maintainer
- to update their communication data within one month.
-
- b. If the search is unsuccessful or no action to resume active
- maintenance is taken by the Current Maintainer, then announce
- within the pertinent community your intention to take over
- maintenance. (If the Work is a LaTeX work, this could be
- done, for example, by posting to comp.text.tex.)
-
- 3a. If the Current Maintainer is reachable and agrees to pass
- maintenance of the Work to you, then this takes effect
- immediately upon announcement.
-
- b. If the Current Maintainer is not reachable and the Copyright
- Holder agrees that maintenance of the Work be passed to you,
- then this takes effect immediately upon announcement.
-
- 4. If you make an `intention announcement' as described in 2b. above
- and after three months your intention is challenged neither by
- the Current Maintainer nor by the Copyright Holder nor by other
- people, then you may arrange for the Work to be changed so as
- to name you as the (new) Current Maintainer.
-
- 5. If the previously unreachable Current Maintainer becomes
- reachable once more within three months of a change completed
- under the terms of 3b) or 4), then that Current Maintainer must
- become or remain the Current Maintainer upon request provided
- they then update their communication data within one month.
-
-A change in the Current Maintainer does not, of itself, alter the fact
-that the Work is distributed under the LPPL license.
-
-If you become the Current Maintainer of the Work, you should
-immediately provide, within the Work, a prominent and unambiguous
-statement of your status as Current Maintainer. You should also
-announce your new status to the same pertinent community as
-in 2b) above.
-
-
-WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE
-======================================================
-
-This section contains important instructions, examples, and
-recommendations for authors who are considering distributing their
-works under this license. These authors are addressed as `you' in
-this section.
-
-Choosing This License or Another License
-----------------------------------------
-
-If for any part of your work you want or need to use *distribution*
-conditions that differ significantly from those in this license, then
-do not refer to this license anywhere in your work but, instead,
-distribute your work under a different license. You may use the text
-of this license as a model for your own license, but your license
-should not refer to the LPPL or otherwise give the impression that
-your work is distributed under the LPPL.
-
-The document `modguide.tex' in the base LaTeX distribution explains
-the motivation behind the conditions of this license. It explains,
-for example, why distributing LaTeX under the GNU General Public
-License (GPL) was considered inappropriate. Even if your work is
-unrelated to LaTeX, the discussion in `modguide.tex' may still be
-relevant, and authors intending to distribute their works under any
-license are encouraged to read it.
-
-A Recommendation on Modification Without Distribution
------------------------------------------------------
-
-It is wise never to modify a component of the Work, even for your own
-personal use, without also meeting the above conditions for
-distributing the modified component. While you might intend that such
-modifications will never be distributed, often this will happen by
-accident -- you may forget that you have modified that component; or
-it may not occur to you when allowing others to access the modified
-version that you are thus distributing it and violating the conditions
-of this license in ways that could have legal implications and, worse,
-cause problems for the community. It is therefore usually in your
-best interest to keep your copy of the Work identical with the public
-one. Many works provide ways to control the behavior of that work
-without altering any of its licensed components.
-
-How to Use This License
------------------------
-
-To use this license, place in each of the components of your work both
-an explicit copyright notice including your name and the year the work
-was authored and/or last substantially modified. Include also a
-statement that the distribution and/or modification of that
-component is constrained by the conditions in this license.
-
-Here is an example of such a notice and statement:
-
- %% pig.dtx
- %% Copyright 2005 M. Y. Name
- %
- % This work may be distributed and/or modified under the
- % conditions of the LaTeX Project Public License, either version 1.3
- % of this license or (at your option) any later version.
- % The latest version of this license is in
- % http://www.latex-project.org/lppl.txt
- % and version 1.3 or later is part of all distributions of LaTeX
- % version 2005/12/01 or later.
- %
- % This work has the LPPL maintenance status `maintained'.
- %
- % The Current Maintainer of this work is M. Y. Name.
- %
- % This work consists of the files pig.dtx and pig.ins
- % and the derived file pig.sty.
-
-Given such a notice and statement in a file, the conditions
-given in this license document would apply, with the `Work' referring
-to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being
-generated from `pig.dtx' using `pig.ins'), the `Base Interpreter'
-referring to any `LaTeX-Format', and both `Copyright Holder' and
-`Current Maintainer' referring to the person `M. Y. Name'.
-
-If you do not want the Maintenance section of LPPL to apply to your
-Work, change `maintained' above into `author-maintained'.
-However, we recommend that you use `maintained', as the Maintenance
-section was added in order to ensure that your Work remains useful to
-the community even when you can no longer maintain and support it
-yourself.
-
-Derived Works That Are Not Replacements
----------------------------------------
-
-Several clauses of the LPPL specify means to provide reliability and
-stability for the user community. They therefore concern themselves
-with the case that a Derived Work is intended to be used as a
-(compatible or incompatible) replacement of the original Work. If
-this is not the case (e.g., if a few lines of code are reused for a
-completely different task), then clauses 6b and 6d shall not apply.
-
-
-Important Recommendations
--------------------------
-
- Defining What Constitutes the Work
-
- The LPPL requires that distributions of the Work contain all the
- files of the Work. It is therefore important that you provide a
- way for the licensee to determine which files constitute the Work.
- This could, for example, be achieved by explicitly listing all the
- files of the Work near the copyright notice of each file or by
- using a line such as:
-
- % This work consists of all files listed in manifest.txt.
-
- in that place. In the absence of an unequivocal list it might be
- impossible for the licensee to determine what is considered by you
- to comprise the Work and, in such a case, the licensee would be
- entitled to make reasonable conjectures as to which files comprise
- the Work.
-
diff --git a/src/fonts/nimbus-sans-l/n019003l.afm b/src/fonts/nimbus-sans-l/n019003l.afm
deleted file mode 100644
index 6a6b40c..0000000
--- a/src/fonts/nimbus-sans-l/n019003l.afm
+++ /dev/null
@@ -1,1563 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 14:35:58 2007
-FontName NimbusSanL-Regu
-FullName Nimbus Sans L Regular
-FamilyName Nimbus Sans L
-Weight Regular
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle 0
-IsFixedPitch false
-UnderlinePosition -151
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -174 -285 1022 953
-CapHeight 729
-XHeight 524
-Ascender 729
-Descender -218
-StartCharMetrics 563
-C 0 ; WX 278 ; N .notdef ; B 0 0 0 0 ;
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 278 ; N exclam ; B 124 0 208 729 ;
-C 34 ; WX 355 ; N quotedbl ; B 52 464 305 709 ;
-C 35 ; WX 556 ; N numbersign ; B 14 -20 542 697 ;
-C 36 ; WX 556 ; N dollar ; B 32 -126 518 770 ;
-C 37 ; WX 889 ; N percent ; B 29 -20 859 709 ;
-C 38 ; WX 667 ; N ampersand ; B 52 -23 637 709 ;
-C 39 ; WX 221 ; N quoteright ; B 64 497 157 729 ;
-C 40 ; WX 333 ; N parenleft ; B 73 -212 291 729 ;
-C 41 ; WX 333 ; N parenright ; B 38 -212 256 729 ;
-C 42 ; WX 389 ; N asterisk ; B 40 441 343 729 ;
-C 43 ; WX 584 ; N plus ; B 50 -10 534 474 ;
-C 44 ; WX 278 ; N comma ; B 87 -147 192 104 ;
-C 45 ; WX 333 ; N hyphen ; B 46 240 284 312 ;
-C 46 ; WX 278 ; N period ; B 87 0 191 104 ;
-C 47 ; WX 278 ; N slash ; B -8 -20 284 729 ;
-C 48 ; WX 556 ; N zero ; B 43 -23 507 709 ;
-C 49 ; WX 556 ; N one ; B 102 0 347 709 ;
-C 50 ; WX 556 ; N two ; B 34 0 511 709 ;
-C 51 ; WX 556 ; N three ; B 32 -23 506 709 ;
-C 52 ; WX 556 ; N four ; B 28 0 520 709 ;
-C 53 ; WX 556 ; N five ; B 35 -23 513 709 ;
-C 54 ; WX 556 ; N six ; B 43 -23 513 709 ;
-C 55 ; WX 556 ; N seven ; B 46 0 520 709 ;
-C 56 ; WX 556 ; N eight ; B 37 -23 513 709 ;
-C 57 ; WX 556 ; N nine ; B 38 -23 509 709 ;
-C 58 ; WX 278 ; N colon ; B 110 0 214 524 ;
-C 59 ; WX 278 ; N semicolon ; B 110 -147 215 524 ;
-C 60 ; WX 584 ; N less ; B 45 -9 534 474 ;
-C 61 ; WX 584 ; N equal ; B 50 111 534 353 ;
-C 62 ; WX 584 ; N greater ; B 50 -9 539 474 ;
-C 63 ; WX 556 ; N question ; B 77 0 509 741 ;
-C 64 ; WX 1015 ; N at ; B 34 -142 951 741 ;
-C 65 ; WX 667 ; N A ; B 17 0 653 729 ;
-C 66 ; WX 667 ; N B ; B 79 0 623 729 ;
-C 67 ; WX 722 ; N C ; B 48 -23 677 741 ;
-C 68 ; WX 722 ; N D ; B 89 0 667 729 ;
-C 69 ; WX 667 ; N E ; B 90 0 613 729 ;
-C 70 ; WX 611 ; N F ; B 90 0 579 729 ;
-C 71 ; WX 778 ; N G ; B 44 -23 709 741 ;
-C 72 ; WX 722 ; N H ; B 83 0 644 729 ;
-C 73 ; WX 278 ; N I ; B 100 0 194 729 ; L J IJ ;
-C 74 ; WX 500 ; N J ; B 17 -23 426 729 ;
-C 75 ; WX 667 ; N K ; B 79 0 658 729 ;
-C 76 ; WX 556 ; N L ; B 80 0 533 729 ; L periodcentered Ldot ;
-C 77 ; WX 833 ; N M ; B 75 0 761 729 ;
-C 78 ; WX 722 ; N N ; B 76 0 646 729 ; L o afii61352 ;
-C 79 ; WX 778 ; N O ; B 38 -23 742 741 ;
-C 80 ; WX 667 ; N P ; B 91 0 617 729 ;
-C 81 ; WX 778 ; N Q ; B 38 -59 742 741 ;
-C 82 ; WX 722 ; N R ; B 93 0 679 729 ;
-C 83 ; WX 667 ; N S ; B 48 -23 621 741 ;
-C 84 ; WX 611 ; N T ; B 21 0 593 729 ; L M trademark ;
-C 85 ; WX 722 ; N U ; B 85 -23 645 729 ;
-C 86 ; WX 667 ; N V ; B 30 0 645 729 ;
-C 87 ; WX 944 ; N W ; B 22 0 929 729 ;
-C 88 ; WX 667 ; N X ; B 22 0 649 729 ;
-C 89 ; WX 667 ; N Y ; B 13 0 661 729 ;
-C 90 ; WX 611 ; N Z ; B 28 0 583 729 ;
-C 91 ; WX 278 ; N bracketleft ; B 64 -212 250 729 ;
-C 92 ; WX 278 ; N backslash ; B -8 -20 284 729 ;
-C 93 ; WX 278 ; N bracketright ; B 23 -212 209 729 ;
-C 94 ; WX 469 ; N asciicircum ; B 44 329 425 709 ;
-C 95 ; WX 556 ; N underscore ; B -22 -176 578 -126 ;
-C 96 ; WX 222 ; N quoteleft ; B 65 477 158 709 ;
-C 97 ; WX 556 ; N a ; B 42 -23 535 539 ;
-C 98 ; WX 556 ; N b ; B 54 -23 523 729 ;
-C 99 ; WX 500 ; N c ; B 31 -23 477 539 ;
-C 100 ; WX 556 ; N d ; B 26 -23 495 729 ;
-C 101 ; WX 556 ; N e ; B 40 -23 513 539 ;
-C 102 ; WX 278 ; N f ; B 18 0 258 732 ; L l fl ; L i fi ;
-C 103 ; WX 556 ; N g ; B 29 -218 489 539 ;
-C 104 ; WX 556 ; N h ; B 70 0 486 729 ;
-C 105 ; WX 222 ; N i ; B 66 0 150 729 ; L j ij ;
-C 106 ; WX 222 ; N j ; B -18 -218 153 729 ;
-C 107 ; WX 500 ; N k ; B 58 0 502 729 ;
-C 108 ; WX 222 ; N l ; B 68 0 152 729 ; L periodcentered ldot ;
-C 109 ; WX 833 ; N m ; B 70 0 762 539 ;
-C 110 ; WX 556 ; N n ; B 70 0 487 539 ;
-C 111 ; WX 556 ; N o ; B 36 -23 510 539 ;
-C 112 ; WX 556 ; N p ; B 54 -218 523 539 ;
-C 113 ; WX 556 ; N q ; B 26 -218 495 539 ;
-C 114 ; WX 333 ; N r ; B 69 0 321 539 ;
-C 115 ; WX 500 ; N s ; B 34 -23 459 539 ;
-C 116 ; WX 278 ; N t ; B 14 -23 254 668 ;
-C 117 ; WX 556 ; N u ; B 65 -23 482 524 ;
-C 118 ; WX 500 ; N v ; B 10 0 486 524 ;
-C 119 ; WX 722 ; N w ; B 6 0 708 524 ;
-C 120 ; WX 500 ; N x ; B 17 0 473 524 ;
-C 121 ; WX 500 ; N y ; B 20 -218 478 524 ;
-C 122 ; WX 500 ; N z ; B 31 0 457 524 ;
-C 123 ; WX 334 ; N braceleft ; B 43 -212 276 729 ;
-C 124 ; WX 260 ; N bar ; B 100 -212 160 729 ;
-C 125 ; WX 334 ; N braceright ; B 29 -212 262 729 ;
-C 126 ; WX 584 ; N asciitilde ; B 75 268 508 438 ;
-C 161 ; WX 333 ; N exclamdown ; B 121 -205 205 524 ;
-C 162 ; WX 556 ; N cent ; B 52 -120 510 628 ;
-C 163 ; WX 556 ; N sterling ; B 26 -23 535 729 ;
-C 164 ; WX 167 ; N fraction ; B -174 -20 336 709 ;
-C 165 ; WX 556 ; N yen ; B 11 0 545 709 ;
-C 166 ; WX 556 ; N florin ; B 11 -212 542 738 ;
-C 167 ; WX 556 ; N section ; B 43 -213 506 729 ;
-C 168 ; WX 556 ; N currency ; B 67 133 489 551 ;
-C 169 ; WX 191 ; N quotesingle ; B 48 464 142 709 ;
-C 170 ; WX 333 ; N quotedblleft ; B 48 477 299 709 ;
-C 171 ; WX 556 ; N guillemotleft ; B 98 106 455 438 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 91 106 243 438 ;
-C 173 ; WX 333 ; N guilsinglright ; B 85 106 239 438 ;
-C 174 ; WX 500 ; N fi ; B 12 0 436 732 ;
-C 175 ; WX 500 ; N fl ; B 17 0 430 732 ;
-C 177 ; WX 556 ; N endash ; B -5 240 561 312 ;
-C 178 ; WX 556 ; N dagger ; B 38 -177 513 709 ;
-C 179 ; WX 556 ; N daggerdbl ; B 38 -177 513 709 ;
-C 180 ; WX 278 ; N periodcentered ; B 87 302 211 427 ;
-C 182 ; WX 537 ; N paragraph ; B 48 -177 522 729 ;
-C 183 ; WX 350 ; N bullet ; B 50 220 300 470 ;
-C 184 ; WX 222 ; N quotesinglbase ; B 64 -128 158 104 ;
-C 185 ; WX 333 ; N quotedblbase ; B 47 -128 300 104 ;
-C 186 ; WX 333 ; N quotedblright ; B 49 477 302 709 ;
-C 187 ; WX 556 ; N guillemotright ; B 98 106 451 438 ;
-C 188 ; WX 1000 ; N ellipsis ; B 115 0 885 104 ;
-C 189 ; WX 1000 ; N perthousand ; B 9 -22 993 738 ;
-C 191 ; WX 611 ; N questiondown ; B 95 -217 528 524 ;
-C 193 ; WX 333 ; N grave ; B 22 592 231 740 ;
-C 194 ; WX 333 ; N acute ; B 92 592 301 740 ;
-C 195 ; WX 333 ; N circumflex ; B 20 591 307 741 ;
-C 196 ; WX 333 ; N tilde ; B 5 613 319 717 ;
-C 197 ; WX 333 ; N macron ; B 28 631 302 701 ;
-C 198 ; WX 333 ; N breve ; B 15 597 316 732 ;
-C 199 ; WX 333 ; N dotaccent ; B 115 612 219 716 ;
-C 200 ; WX 333 ; N dieresis ; B 30 612 296 715 ;
-C 202 ; WX 333 ; N ring ; B 79 579 255 754 ;
-C 203 ; WX 333 ; N cedilla ; B 39 -214 287 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B -35 590 348 740 ;
-C 206 ; WX 333 ; N ogonek ; B 57 -205 265 0 ;
-C 207 ; WX 333 ; N caron ; B 19 591 306 741 ;
-C 208 ; WX 1000 ; N emdash ; B -9 240 1001 312 ;
-C 225 ; WX 1000 ; N AE ; B 11 0 950 729 ;
-C 227 ; WX 370 ; N ordfeminine ; B 37 303 333 742 ;
-C 232 ; WX 556 ; N Lslash ; B 0 0 552 729 ;
-C 233 ; WX 778 ; N Oslash ; B 30 -23 744 755 ;
-C 234 ; WX 1000 ; N OE ; B 43 -20 959 741 ;
-C 235 ; WX 365 ; N ordmasculine ; B 40 303 324 742 ;
-C 241 ; WX 889 ; N ae ; B 34 -23 845 539 ;
-C 245 ; WX 278 ; N dotlessi ; B 94 0 178 524 ;
-C 248 ; WX 222 ; N lslash ; B 0 0 212 729 ;
-C 249 ; WX 611 ; N oslash ; B 18 -30 529 539 ;
-C 250 ; WX 944 ; N oe ; B 40 -23 899 539 ;
-C 251 ; WX 611 ; N germandbls ; B 126 -20 566 729 ;
-C -1 ; WX 667 ; N Adieresis ; B 17 0 653 914 ;
-C -1 ; WX 667 ; N Aacute ; B 17 0 653 939 ;
-C -1 ; WX 667 ; N Agrave ; B 17 0 653 939 ;
-C -1 ; WX 667 ; N Acircumflex ; B 17 0 653 940 ;
-C -1 ; WX 667 ; N Abreve ; B 17 0 653 931 ;
-C -1 ; WX 667 ; N Atilde ; B 17 0 653 916 ;
-C -1 ; WX 667 ; N Aring ; B 17 0 653 953 ;
-C -1 ; WX 667 ; N Aogonek ; B 17 -205 692 729 ;
-C -1 ; WX 722 ; N Ccedilla ; B 48 -214 677 741 ;
-C -1 ; WX 722 ; N Cacute ; B 48 -23 677 939 ;
-C -1 ; WX 722 ; N Ccaron ; B 48 -23 677 940 ;
-C -1 ; WX 722 ; N Dcaron ; B 89 0 667 940 ;
-C -1 ; WX 667 ; N Edieresis ; B 90 0 613 914 ;
-C -1 ; WX 667 ; N Eacute ; B 90 0 613 939 ;
-C -1 ; WX 667 ; N Egrave ; B 90 0 613 939 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 90 0 613 940 ;
-C -1 ; WX 667 ; N Ecaron ; B 90 0 613 940 ;
-C -1 ; WX 667 ; N Edotaccent ; B 90 0 613 915 ;
-C -1 ; WX 667 ; N Eogonek ; B 90 -205 652 729 ;
-C -1 ; WX 778 ; N Gbreve ; B 44 -23 709 931 ;
-C -1 ; WX 278 ; N Idieresis ; B 9 0 275 907 ;
-C -1 ; WX 278 ; N Iacute ; B 71 0 280 939 ;
-C -1 ; WX 278 ; N Igrave ; B 1 0 210 939 ;
-C -1 ; WX 278 ; N Icircumflex ; B -1 0 286 940 ;
-C -1 ; WX 278 ; N Idotaccent ; B 92 0 196 915 ;
-C -1 ; WX 556 ; N Lacute ; B 70 0 533 939 ;
-C -1 ; WX 556 ; N Lcaron ; B 80 0 533 729 ;
-C -1 ; WX 722 ; N Nacute ; B 76 0 646 939 ;
-C -1 ; WX 722 ; N Ncaron ; B 76 0 646 940 ;
-C -1 ; WX 722 ; N Ntilde ; B 76 0 646 916 ;
-C -1 ; WX 778 ; N Odieresis ; B 38 -23 742 914 ;
-C -1 ; WX 778 ; N Oacute ; B 38 -23 742 939 ;
-C -1 ; WX 778 ; N Ograve ; B 38 -23 742 939 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 38 -23 742 940 ;
-C -1 ; WX 778 ; N Otilde ; B 38 -23 742 916 ;
-C -1 ; WX 778 ; N Ohungarumlaut ; B 38 -23 742 939 ;
-C -1 ; WX 722 ; N Racute ; B 93 0 679 939 ;
-C -1 ; WX 722 ; N Rcaron ; B 93 0 679 940 ;
-C -1 ; WX 667 ; N Sacute ; B 48 -23 621 939 ;
-C -1 ; WX 667 ; N Scaron ; B 48 -23 621 940 ;
-C -1 ; WX 667 ; N Scedilla ; B 47 -214 621 741 ;
-C -1 ; WX 611 ; N Tcaron ; B 21 0 593 940 ;
-C -1 ; WX 722 ; N Udieresis ; B 85 -23 645 914 ;
-C -1 ; WX 722 ; N Uacute ; B 85 -23 645 939 ;
-C -1 ; WX 722 ; N Ugrave ; B 85 -23 645 939 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 85 -23 645 940 ;
-C -1 ; WX 722 ; N Uring ; B 85 -23 645 953 ;
-C -1 ; WX 722 ; N Uhungarumlaut ; B 85 -23 645 939 ;
-C -1 ; WX 666 ; N Yacute ; B 13 0 661 939 ;
-C -1 ; WX 611 ; N Zacute ; B 28 0 583 939 ;
-C -1 ; WX 611 ; N Zcaron ; B 28 0 583 940 ;
-C -1 ; WX 611 ; N Zdotaccent ; B 28 0 583 915 ;
-C -1 ; WX 667 ; N Amacron ; B 17 0 653 900 ;
-C -1 ; WX 611 ; N Tcommaaccent ; B 21 -285 593 729 ;
-C -1 ; WX 667 ; N Ydieresis ; B 13 0 661 914 ;
-C -1 ; WX 667 ; N Emacron ; B 90 0 613 900 ;
-C -1 ; WX 278 ; N Imacron ; B 20 0 274 900 ;
-C -1 ; WX 278 ; N Iogonek ; B 66 -204 234 729 ;
-C -1 ; WX 667 ; N Kcommaaccent ; B 79 -285 658 729 ;
-C -1 ; WX 556 ; N Lcommaaccent ; B 80 -285 533 729 ;
-C -1 ; WX 722 ; N Ncommaaccent ; B 76 -285 646 729 ;
-C -1 ; WX 778 ; N Omacron ; B 38 -23 742 900 ;
-C -1 ; WX 722 ; N Rcommaaccent ; B 93 -285 679 729 ;
-C -1 ; WX 778 ; N Gcommaaccent ; B 44 -285 709 741 ;
-C -1 ; WX 722 ; N Umacron ; B 85 -23 645 900 ;
-C -1 ; WX 722 ; N Uogonek ; B 85 -205 645 729 ;
-C -1 ; WX 556 ; N adieresis ; B 42 -23 535 715 ;
-C -1 ; WX 556 ; N aacute ; B 42 -23 535 740 ;
-C -1 ; WX 556 ; N agrave ; B 42 -23 535 740 ;
-C -1 ; WX 556 ; N acircumflex ; B 42 -23 535 741 ;
-C -1 ; WX 556 ; N abreve ; B 42 -23 535 732 ;
-C -1 ; WX 556 ; N atilde ; B 42 -23 535 717 ;
-C -1 ; WX 556 ; N aring ; B 42 -23 535 754 ;
-C -1 ; WX 556 ; N aogonek ; B 43 -205 596 539 ;
-C -1 ; WX 500 ; N cacute ; B 31 -23 477 740 ;
-C -1 ; WX 500 ; N ccaron ; B 31 -23 477 741 ;
-C -1 ; WX 500 ; N ccedilla ; B 31 -214 477 539 ;
-C -1 ; WX 635 ; N dcaron ; B 26 -23 648 729 ;
-C -1 ; WX 556 ; N edieresis ; B 40 -23 513 715 ;
-C -1 ; WX 556 ; N eacute ; B 40 -23 513 740 ;
-C -1 ; WX 556 ; N egrave ; B 40 -23 513 740 ;
-C -1 ; WX 556 ; N ecircumflex ; B 40 -23 513 741 ;
-C -1 ; WX 556 ; N ecaron ; B 40 -23 513 741 ;
-C -1 ; WX 556 ; N edotaccent ; B 40 -23 513 716 ;
-C -1 ; WX 556 ; N eogonek ; B 40 -204 514 539 ;
-C -1 ; WX 556 ; N gbreve ; B 29 -218 489 732 ;
-C -1 ; WX 278 ; N idieresis ; B 3 0 269 708 ;
-C -1 ; WX 278 ; N iacute ; B 65 0 274 740 ;
-C -1 ; WX 278 ; N igrave ; B -5 0 204 740 ;
-C -1 ; WX 278 ; N icircumflex ; B -7 0 280 741 ;
-C -1 ; WX 222 ; N lacute ; B 63 0 272 939 ;
-C -1 ; WX 292 ; N lcaron ; B 68 0 305 729 ;
-C -1 ; WX 556 ; N nacute ; B 70 0 487 740 ;
-C -1 ; WX 556 ; N ncaron ; B 70 0 487 741 ;
-C -1 ; WX 556 ; N ntilde ; B 70 0 487 717 ;
-C -1 ; WX 556 ; N odieresis ; B 36 -23 510 715 ;
-C -1 ; WX 556 ; N oacute ; B 36 -23 510 740 ;
-C -1 ; WX 556 ; N ograve ; B 36 -23 510 740 ;
-C -1 ; WX 556 ; N ocircumflex ; B 36 -23 510 741 ;
-C -1 ; WX 556 ; N otilde ; B 36 -23 510 717 ;
-C -1 ; WX 556 ; N ohungarumlaut ; B 36 -23 526 740 ;
-C -1 ; WX 333 ; N racute ; B 69 0 331 740 ;
-C -1 ; WX 500 ; N sacute ; B 34 -23 459 740 ;
-C -1 ; WX 500 ; N scaron ; B 34 -23 459 741 ;
-C -1 ; WX 500 ; N scommaaccent ; B 34 -285 459 539 ;
-C -1 ; WX 308 ; N tcaron ; B 14 -23 321 800 ;
-C -1 ; WX 556 ; N udieresis ; B 65 -23 482 715 ;
-C -1 ; WX 556 ; N uacute ; B 65 -23 482 740 ;
-C -1 ; WX 556 ; N ugrave ; B 65 -23 482 740 ;
-C -1 ; WX 556 ; N ucircumflex ; B 65 -23 482 741 ;
-C -1 ; WX 556 ; N uring ; B 65 -23 482 754 ;
-C -1 ; WX 556 ; N uhungarumlaut ; B 65 -23 530 740 ;
-C -1 ; WX 500 ; N yacute ; B 20 -218 478 740 ;
-C -1 ; WX 500 ; N zacute ; B 31 0 457 740 ;
-C -1 ; WX 500 ; N zcaron ; B 31 0 457 741 ;
-C -1 ; WX 500 ; N zdotaccent ; B 31 0 457 716 ;
-C -1 ; WX 500 ; N ydieresis ; B 20 -218 478 715 ;
-C -1 ; WX 278 ; N tcommaaccent ; B 14 -285 254 668 ;
-C -1 ; WX 556 ; N amacron ; B 42 -23 535 701 ;
-C -1 ; WX 556 ; N emacron ; B 40 -23 513 701 ;
-C -1 ; WX 222 ; N imacron ; B -16 0 231 701 ;
-C -1 ; WX 500 ; N kcommaaccent ; B 58 -285 502 729 ;
-C -1 ; WX 222 ; N lcommaaccent ; B 63 -285 163 729 ;
-C -1 ; WX 556 ; N ncommaaccent ; B 70 -285 487 539 ;
-C -1 ; WX 556 ; N omacron ; B 36 -23 510 701 ;
-C -1 ; WX 333 ; N rcommaaccent ; B 65 -285 321 539 ;
-C -1 ; WX 556 ; N umacron ; B 65 -23 482 701 ;
-C -1 ; WX 556 ; N uogonek ; B 65 -204 521 524 ;
-C -1 ; WX 333 ; N rcaron ; B 48 0 335 741 ;
-C -1 ; WX 500 ; N scedilla ; B 34 -214 459 539 ;
-C -1 ; WX 556 ; N gcommaaccent ; B 29 -218 489 817 ;
-C -1 ; WX 222 ; N iogonek ; B 25 -204 190 729 ;
-C -1 ; WX 667 ; N Scommaaccent ; B 48 -285 621 741 ;
-C -1 ; WX 722 ; N Eth ; B 20 0 667 729 ;
-C -1 ; WX 722 ; N Dcroat ; B 20 0 667 729 ;
-C -1 ; WX 666 ; N Thorn ; B 91 0 616 729 ;
-C -1 ; WX 556 ; N dcroat ; B 26 -23 557 729 ;
-C -1 ; WX 556 ; N eth ; B 36 -23 510 743 ;
-C -1 ; WX 555 ; N thorn ; B 54 -218 522 714 ;
-C -1 ; WX 556 ; N Euro ; B 2 -23 543 709 ;
-C -1 ; WX 351 ; N onesuperior ; B 61 284 222 709 ;
-C -1 ; WX 351 ; N twosuperior ; B 19 284 326 709 ;
-C -1 ; WX 351 ; N threesuperior ; B 16 270 322 709 ;
-C -1 ; WX 606 ; N degree ; B 151 383 454 686 ;
-C -1 ; WX 584 ; N minus ; B 40 197 544 267 ;
-C -1 ; WX 584 ; N multiply ; B 95 34 488 427 ;
-C -1 ; WX 584 ; N divide ; B 50 0 534 472 ;
-C -1 ; WX 1000 ; N trademark ; B 63 292 938 729 ;
-C -1 ; WX 584 ; N plusminus ; B 50 -11 534 623 ;
-C -1 ; WX 869 ; N onehalf ; B 61 -20 844 709 ;
-C -1 ; WX 869 ; N onequarter ; B 61 -20 849 709 ;
-C -1 ; WX 869 ; N threequarters ; B 16 -20 849 709 ;
-C -1 ; WX 333 ; N commaaccent ; B 116 -285 216 -60 ;
-C -1 ; WX 737 ; N copyright ; B -13 -22 751 742 ;
-C -1 ; WX 737 ; N registered ; B -13 -22 751 742 ;
-C -1 ; WX 489 ; N lozenge ; B 16 0 462 744 ;
-C -1 ; WX 711 ; N Delta ; B 10 0 701 729 ;
-C -1 ; WX 548 ; N notequal ; B 32 -25 516 486 ;
-C -1 ; WX 542 ; N radical ; B 7 -36 512 913 ;
-C -1 ; WX 584 ; N lessequal ; B 45 -11 534 639 ;
-C -1 ; WX 584 ; N greaterequal ; B 45 -11 534 639 ;
-C -1 ; WX 584 ; N logicalnot ; B 40 86 544 375 ;
-C -1 ; WX 711 ; N summation ; B 17 -97 694 760 ;
-C -1 ; WX 490 ; N partialdiff ; B 22 -15 458 750 ;
-C -1 ; WX 260 ; N brokenbar ; B 100 -212 160 729 ;
-C -1 ; WX 556 ; N mu ; B 65 -220 544 524 ;
-C -1 ; WX 667 ; N afii10017 ; B 17 0 653 729 ;
-C -1 ; WX 667 ; N afii10018 ; B 79 0 623 729 ;
-C -1 ; WX 667 ; N afii10019 ; B 79 0 623 729 ;
-C -1 ; WX 611 ; N afii10020 ; B 79 0 568 729 ;
-C -1 ; WX 812 ; N afii10021 ; B 34 -135 778 729 ;
-C -1 ; WX 667 ; N afii10022 ; B 79 0 602 729 ;
-C -1 ; WX 667 ; N afii10023 ; B 79 0 602 914 ;
-C -1 ; WX 1023 ; N afii10024 ; B 63 0 948 729 ;
-C -1 ; WX 667 ; N afii10025 ; B 48 -23 621 741 ;
-C -1 ; WX 728 ; N afii10026 ; B 79 0 649 729 ;
-C -1 ; WX 728 ; N afii10027 ; B 79 0 649 924 ;
-C -1 ; WX 667 ; N afii10028 ; B 79 0 621 729 ;
-C -1 ; WX 673 ; N afii10029 ; B 33 -10 594 729 ;
-C -1 ; WX 844 ; N afii10030 ; B 79 0 765 729 ;
-C -1 ; WX 719 ; N afii10031 ; B 79 0 640 729 ;
-C -1 ; WX 778 ; N afii10032 ; B 38 -23 742 741 ;
-C -1 ; WX 719 ; N afii10033 ; B 79 0 640 729 ;
-C -1 ; WX 667 ; N afii10034 ; B 79 0 605 729 ;
-C -1 ; WX 722 ; N afii10035 ; B 48 -23 677 741 ;
-C -1 ; WX 611 ; N afii10036 ; B 21 0 593 729 ;
-C -1 ; WX 650 ; N afii10037 ; B 26 0 619 729 ;
-C -1 ; WX 936 ; N afii10038 ; B 64 0 829 729 ;
-C -1 ; WX 667 ; N afii10039 ; B 22 0 641 729 ;
-C -1 ; WX 741 ; N afii10040 ; B 79 -135 707 729 ;
-C -1 ; WX 648 ; N afii10041 ; B 79 0 569 729 ;
-C -1 ; WX 828 ; N afii10042 ; B 79 0 749 729 ;
-C -1 ; WX 850 ; N afii10043 ; B 79 -135 816 729 ;
-C -1 ; WX 897 ; N afii10044 ; B 81 0 856 729 ;
-C -1 ; WX 872 ; N afii10045 ; B 79 0 793 729 ;
-C -1 ; WX 667 ; N afii10046 ; B 79 0 623 729 ;
-C -1 ; WX 722 ; N afii10047 ; B 48 -23 677 741 ;
-C -1 ; WX 1032 ; N afii10048 ; B 83 -23 958 741 ;
-C -1 ; WX 702 ; N afii10049 ; B 32 0 623 729 ;
-C -1 ; WX 556 ; N afii10065 ; B 42 -23 535 539 ;
-C -1 ; WX 556 ; N afii10066 ; B 36 -23 510 775 ;
-C -1 ; WX 522 ; N afii10067 ; B 70 0 468 524 ;
-C -1 ; WX 430 ; N afii10068 ; B 70 0 380 524 ;
-C -1 ; WX 602 ; N afii10069 ; B 30 -120 572 524 ;
-C -1 ; WX 556 ; N afii10070 ; B 40 -23 513 539 ;
-C -1 ; WX 556 ; N afii10071 ; B 40 -23 513 716 ;
-C -1 ; WX 837 ; N afii10072 ; B 44 0 789 524 ;
-C -1 ; WX 500 ; N afii10073 ; B 34 -23 459 539 ;
-C -1 ; WX 567 ; N afii10074 ; B 70 0 497 524 ;
-C -1 ; WX 567 ; N afii10075 ; B 70 0 497 699 ;
-C -1 ; WX 510 ; N afii10076 ; B 70 0 484 524 ;
-C -1 ; WX 557 ; N afii10077 ; B 70 -10 487 524 ;
-C -1 ; WX 618 ; N afii10078 ; B 70 0 548 524 ;
-C -1 ; WX 558 ; N afii10079 ; B 70 0 488 524 ;
-C -1 ; WX 556 ; N afii10080 ; B 36 -23 510 539 ;
-C -1 ; WX 557 ; N afii10081 ; B 70 0 487 524 ;
-C -1 ; WX 576 ; N afii10082 ; B 54 -218 523 539 ;
-C -1 ; WX 500 ; N afii10083 ; B 31 -23 477 539 ;
-C -1 ; WX 496 ; N afii10084 ; B 60 0 432 524 ;
-C -1 ; WX 500 ; N afii10085 ; B 20 -218 478 524 ;
-C -1 ; WX 912 ; N afii10086 ; B 61 -218 850 674 ;
-C -1 ; WX 500 ; N afii10087 ; B 17 0 473 524 ;
-C -1 ; WX 578 ; N afii10088 ; B 70 -120 548 524 ;
-C -1 ; WX 520 ; N afii10089 ; B 70 0 450 524 ;
-C -1 ; WX 692 ; N afii10090 ; B 70 0 622 524 ;
-C -1 ; WX 712 ; N afii10091 ; B 70 -120 682 524 ;
-C -1 ; WX 734 ; N afii10092 ; B 57 0 653 524 ;
-C -1 ; WX 690 ; N afii10093 ; B 70 0 620 524 ;
-C -1 ; WX 552 ; N afii10094 ; B 70 0 483 524 ;
-C -1 ; WX 500 ; N afii10095 ; B 31 -23 477 539 ;
-C -1 ; WX 758 ; N afii10096 ; B 70 -23 721 539 ;
-C -1 ; WX 543 ; N afii10097 ; B 14 0 473 524 ;
-C -1 ; WX 667 ; N uni0400 ; B 90 0 613 917 ;
-C -1 ; WX 738 ; N afii10051 ; B 21 -174 701 729 ;
-C -1 ; WX 611 ; N afii10052 ; B 90 0 579 917 ;
-C -1 ; WX 722 ; N afii10053 ; B 48 -23 677 741 ;
-C -1 ; WX 667 ; N afii10054 ; B 48 -23 621 741 ;
-C -1 ; WX 278 ; N afii10055 ; B 100 0 194 729 ;
-C -1 ; WX 278 ; N afii10056 ; B 8 0 274 908 ;
-C -1 ; WX 500 ; N afii10057 ; B 17 -23 426 729 ;
-C -1 ; WX 1080 ; N afii10058 ; B 83 0 1022 729 ;
-C -1 ; WX 1014 ; N afii10059 ; B 83 0 972 729 ;
-C -1 ; WX 748 ; N afii10060 ; B 21 0 711 729 ;
-C -1 ; WX 667 ; N afii10061 ; B 79 0 658 917 ;
-C -1 ; WX 722 ; N uni040D ; B 76 0 646 917 ;
-C -1 ; WX 650 ; N afii10062 ; B 26 0 619 904 ;
-C -1 ; WX 722 ; N afii10145 ; B 83 -135 645 729 ;
-C -1 ; WX 556 ; N uni0450 ; B 40 -23 513 740 ;
-C -1 ; WX 582 ; N afii10099 ; B 15 -143 512 729 ;
-C -1 ; WX 430 ; N afii10100 ; B 70 0 365 712 ;
-C -1 ; WX 500 ; N afii10101 ; B 31 -23 477 539 ;
-C -1 ; WX 500 ; N afii10102 ; B 34 -23 459 539 ;
-C -1 ; WX 222 ; N afii10103 ; B 66 0 150 729 ;
-C -1 ; WX 278 ; N afii10104 ; B 3 0 269 708 ;
-C -1 ; WX 222 ; N afii10105 ; B -18 -218 153 729 ;
-C -1 ; WX 884 ; N afii10106 ; B 70 0 815 524 ;
-C -1 ; WX 885 ; N afii10107 ; B 70 0 816 524 ;
-C -1 ; WX 582 ; N afii10108 ; B 15 0 512 729 ;
-C -1 ; WX 500 ; N afii10109 ; B 58 0 502 712 ;
-C -1 ; WX 556 ; N uni045D ; B 70 0 487 712 ;
-C -1 ; WX 500 ; N afii10110 ; B 20 -218 478 699 ;
-C -1 ; WX 556 ; N afii10193 ; B 70 -120 488 524 ;
-C -1 ; WX 667 ; N uni048C ; B -10 0 623 729 ;
-C -1 ; WX 552 ; N uni048D ; B 8 0 488 524 ;
-C -1 ; WX 667 ; N uni048E ; B 91 0 617 729 ;
-C -1 ; WX 556 ; N uni048F ; B 54 -218 524 539 ;
-C -1 ; WX 611 ; N afii10050 ; B 90 0 579 825 ;
-C -1 ; WX 430 ; N afii10098 ; B 70 0 365 629 ;
-C -1 ; WX 611 ; N uni0492 ; B 4 0 568 729 ;
-C -1 ; WX 430 ; N uni0493 ; B 8 0 380 524 ;
-C -1 ; WX 611 ; N uni0494 ; B 90 -174 579 729 ;
-C -1 ; WX 490 ; N uni0495 ; B 70 -143 427 524 ;
-C -1 ; WX 1023 ; N uni0496 ; B 63 -135 948 729 ;
-C -1 ; WX 837 ; N uni0497 ; B 14 -120 819 524 ;
-C -1 ; WX 667 ; N uni0498 ; B 48 -205 621 741 ;
-C -1 ; WX 500 ; N uni0499 ; B 34 -205 459 539 ;
-C -1 ; WX 667 ; N uni049A ; B 79 -135 621 729 ;
-C -1 ; WX 510 ; N uni049B ; B 70 -120 484 524 ;
-C -1 ; WX 667 ; N uni049C ; B 79 0 664 729 ;
-C -1 ; WX 500 ; N uni049D ; B 58 0 502 524 ;
-C -1 ; WX 667 ; N uni049E ; B -6 0 658 729 ;
-C -1 ; WX 500 ; N uni049F ; B -2 0 502 524 ;
-C -1 ; WX 900 ; N uni04A0 ; B 81 0 891 729 ;
-C -1 ; WX 683 ; N uni04A1 ; B 57 0 685 524 ;
-C -1 ; WX 722 ; N uni04A2 ; B 83 -135 711 729 ;
-C -1 ; WX 556 ; N uni04A3 ; B 70 -120 548 524 ;
-C -1 ; WX 1000 ; N uni04A4 ; B 83 0 968 729 ;
-C -1 ; WX 764 ; N uni04A5 ; B 70 0 699 524 ;
-C -1 ; WX 1061 ; N uni04A6 ; B 83 -174 1001 729 ;
-C -1 ; WX 826 ; N uni04A7 ; B 70 -143 760 524 ;
-C -1 ; WX 722 ; N uni04A8 ; B 48 -23 706 741 ;
-C -1 ; WX 500 ; N uni04A9 ; B 31 -23 485 539 ;
-C -1 ; WX 722 ; N uni04AA ; B 48 -205 677 741 ;
-C -1 ; WX 500 ; N uni04AB ; B 31 -205 477 539 ;
-C -1 ; WX 611 ; N uni04AC ; B 21 -135 593 729 ;
-C -1 ; WX 496 ; N uni04AD ; B 60 -120 432 524 ;
-C -1 ; WX 667 ; N uni04AE ; B 13 0 661 729 ;
-C -1 ; WX 667 ; N uni04AF ; B 53 -200 621 524 ;
-C -1 ; WX 667 ; N uni04B0 ; B 13 0 661 729 ;
-C -1 ; WX 667 ; N uni04B1 ; B 53 -200 621 524 ;
-C -1 ; WX 667 ; N uni04B2 ; B 22 -135 649 729 ;
-C -1 ; WX 500 ; N uni04B3 ; B 17 -120 473 524 ;
-C -1 ; WX 942 ; N uni04B4 ; B 21 -135 904 729 ;
-C -1 ; WX 732 ; N uni04B5 ; B 60 -120 692 524 ;
-C -1 ; WX 648 ; N uni04B6 ; B 79 -135 636 729 ;
-C -1 ; WX 520 ; N uni04B7 ; B 70 -120 511 524 ;
-C -1 ; WX 648 ; N uni04B8 ; B 79 0 569 729 ;
-C -1 ; WX 520 ; N uni04B9 ; B 70 0 450 524 ;
-C -1 ; WX 648 ; N uni04BA ; B 79 0 569 729 ;
-C -1 ; WX 520 ; N uni04BB ; B 70 0 450 524 ;
-C -1 ; WX 927 ; N uni04BC ; B 47 -23 882 757 ;
-C -1 ; WX 716 ; N uni04BD ; B 42 -23 673 539 ;
-C -1 ; WX 927 ; N uni04BE ; B 47 -205 882 757 ;
-C -1 ; WX 716 ; N uni04BF ; B 42 -205 673 539 ;
-C -1 ; WX 278 ; N uni04C0 ; B 100 0 194 729 ;
-C -1 ; WX 1023 ; N uni04C1 ; B 63 0 948 904 ;
-C -1 ; WX 837 ; N uni04C2 ; B 14 0 819 699 ;
-C -1 ; WX 667 ; N uni04C3 ; B 79 -174 655 729 ;
-C -1 ; WX 500 ; N uni04C4 ; B 58 -143 470 524 ;
-C -1 ; WX 722 ; N uni04C7 ; B 83 -174 644 729 ;
-C -1 ; WX 556 ; N uni04C8 ; B 70 -143 488 524 ;
-C -1 ; WX 648 ; N uni04CB ; B 79 -135 569 729 ;
-C -1 ; WX 520 ; N uni04CC ; B 70 -120 450 524 ;
-C -1 ; WX 667 ; N uni04D0 ; B 17 0 653 904 ;
-C -1 ; WX 556 ; N uni04D1 ; B 42 -23 535 699 ;
-C -1 ; WX 667 ; N uni04D2 ; B 17 0 653 872 ;
-C -1 ; WX 556 ; N uni04D3 ; B 42 -23 535 667 ;
-C -1 ; WX 1000 ; N uni04D4 ; B 11 0 950 729 ;
-C -1 ; WX 889 ; N uni04D5 ; B 34 -23 845 539 ;
-C -1 ; WX 667 ; N uni04D6 ; B 90 0 613 904 ;
-C -1 ; WX 556 ; N uni04D7 ; B 40 -23 513 699 ;
-C -1 ; WX 722 ; N uni04D8 ; B 47 -23 677 741 ;
-C -1 ; WX 556 ; N afii10846 ; B 40 -23 513 539 ;
-C -1 ; WX 722 ; N uni04DA ; B 47 -23 677 904 ;
-C -1 ; WX 556 ; N uni04DB ; B 40 -23 513 702 ;
-C -1 ; WX 1023 ; N uni04DC ; B 63 0 948 872 ;
-C -1 ; WX 837 ; N uni04DD ; B 14 0 819 667 ;
-C -1 ; WX 667 ; N uni04DE ; B 48 -23 621 872 ;
-C -1 ; WX 500 ; N uni04DF ; B 34 -23 459 667 ;
-C -1 ; WX 667 ; N uni04E0 ; B 48 -23 624 729 ;
-C -1 ; WX 500 ; N uni04E1 ; B 34 -23 459 524 ;
-C -1 ; WX 722 ; N uni04E2 ; B 76 0 646 839 ;
-C -1 ; WX 556 ; N uni04E3 ; B 70 0 487 634 ;
-C -1 ; WX 722 ; N uni04E4 ; B 76 0 646 872 ;
-C -1 ; WX 556 ; N uni04E5 ; B 70 0 487 667 ;
-C -1 ; WX 778 ; N uni04E6 ; B 38 -23 742 872 ;
-C -1 ; WX 556 ; N uni04E7 ; B 36 -23 510 667 ;
-C -1 ; WX 778 ; N uni04E8 ; B 38 -23 742 741 ;
-C -1 ; WX 556 ; N uni04E9 ; B 36 -23 510 539 ;
-C -1 ; WX 778 ; N uni04EA ; B 38 -23 742 872 ;
-C -1 ; WX 556 ; N uni04EB ; B 36 -23 510 667 ;
-C -1 ; WX 722 ; N uni04EC ; B 48 -23 677 872 ;
-C -1 ; WX 500 ; N uni04ED ; B 31 -23 477 667 ;
-C -1 ; WX 650 ; N uni04EE ; B 26 0 619 839 ;
-C -1 ; WX 500 ; N uni04EF ; B 20 -218 478 634 ;
-C -1 ; WX 650 ; N uni04F0 ; B 26 0 619 872 ;
-C -1 ; WX 500 ; N uni04F1 ; B 20 -218 478 667 ;
-C -1 ; WX 650 ; N uni04F2 ; B 26 0 619 919 ;
-C -1 ; WX 500 ; N uni04F3 ; B 20 -218 478 714 ;
-C -1 ; WX 648 ; N uni04F4 ; B 79 0 569 904 ;
-C -1 ; WX 520 ; N uni04F5 ; B 70 0 450 702 ;
-C -1 ; WX 886 ; N uni04F8 ; B 79 0 804 872 ;
-C -1 ; WX 748 ; N uni04F9 ; B 70 0 661 667 ;
-C -1 ; WX 430 ; N uniF6C4 ; B 70 0 380 524 ;
-C -1 ; WX 556 ; N uniF6C5 ; B 36 -23 510 775 ;
-C -1 ; WX 602 ; N uniF6C6 ; B 30 -120 572 524 ;
-C -1 ; WX 557 ; N uniF6C7 ; B 70 0 487 524 ;
-C -1 ; WX 496 ; N uniF6C8 ; B 60 0 432 524 ;
-C -1 ; WX 722 ; N Ccircumflex ; B 48 -23 677 929 ;
-C -1 ; WX 500 ; N ccircumflex ; B 31 -23 477 714 ;
-C -1 ; WX 722 ; N Cdotaccent ; B 48 -23 677 893 ;
-C -1 ; WX 500 ; N cdotaccent ; B 31 -23 477 668 ;
-C -1 ; WX 667 ; N Ebreve ; B 90 0 613 904 ;
-C -1 ; WX 556 ; N ebreve ; B 40 -23 513 699 ;
-C -1 ; WX 778 ; N Gcircumflex ; B 44 -23 709 939 ;
-C -1 ; WX 556 ; N gcircumflex ; B 29 -218 489 734 ;
-C -1 ; WX 778 ; N Gdotaccent ; B 44 -23 709 893 ;
-C -1 ; WX 556 ; N gdotaccent ; B 29 -218 489 698 ;
-C -1 ; WX 722 ; N Hcircumflex ; B 83 0 644 919 ;
-C -1 ; WX 556 ; N hcircumflex ; B -32 0 486 919 ;
-C -1 ; WX 785 ; N Hbar ; B 38 0 752 729 ;
-C -1 ; WX 556 ; N hbar ; B 22 0 486 729 ;
-C -1 ; WX 278 ; N Itilde ; B -10 0 304 873 ;
-C -1 ; WX 278 ; N itilde ; B -21 0 293 668 ;
-C -1 ; WX 278 ; N Ibreve ; B -4 0 297 904 ;
-C -1 ; WX 278 ; N ibreve ; B -14 0 287 699 ;
-C -1 ; WX 700 ; N IJ ; B 100 -23 626 729 ;
-C -1 ; WX 374 ; N ij ; B 66 -218 305 729 ;
-C -1 ; WX 500 ; N Jcircumflex ; B 17 -23 523 919 ;
-C -1 ; WX 222 ; N jcircumflex ; B -32 -218 255 785 ;
-C -1 ; WX 500 ; N kgreenlandic ; B 58 0 502 524 ;
-C -1 ; WX 556 ; N Ldot ; B 80 0 533 729 ;
-C -1 ; WX 404 ; N ldot ; B 68 0 357 729 ;
-C -1 ; WX 556 ; N napostrophe ; B 64 0 487 789 ;
-C -1 ; WX 722 ; N Eng ; B 76 -174 646 729 ;
-C -1 ; WX 556 ; N eng ; B 70 -143 487 539 ;
-C -1 ; WX 778 ; N Obreve ; B 38 -23 742 904 ;
-C -1 ; WX 556 ; N obreve ; B 36 -23 510 699 ;
-C -1 ; WX 667 ; N Scircumflex ; B 48 -23 621 919 ;
-C -1 ; WX 500 ; N scircumflex ; B 34 -23 459 714 ;
-C -1 ; WX 611 ; N Tbar ; B 21 0 593 729 ;
-C -1 ; WX 278 ; N tbar ; B 13 -23 253 668 ;
-C -1 ; WX 722 ; N Utilde ; B 85 -23 645 873 ;
-C -1 ; WX 556 ; N utilde ; B 65 -23 482 668 ;
-C -1 ; WX 722 ; N Ubreve ; B 85 -23 645 904 ;
-C -1 ; WX 556 ; N ubreve ; B 65 -23 482 699 ;
-C -1 ; WX 944 ; N Wcircumflex ; B 22 0 929 919 ;
-C -1 ; WX 722 ; N wcircumflex ; B 6 0 708 714 ;
-C -1 ; WX 667 ; N Ycircumflex ; B 13 0 661 919 ;
-C -1 ; WX 500 ; N ycircumflex ; B 20 -218 478 714 ;
-C -1 ; WX 278 ; N longs ; B 18 0 258 732 ;
-C -1 ; WX 1008 ; N afii61352 ; B 76 0 978 729 ;
-C -1 ; WX 756 ; N infinity ; B 38 114 710 500 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 974
-KPX quoteright A -72
-KPX quoteright AE -85
-KPX quoteright Aacute -72
-KPX quoteright Adieresis -72
-KPX quoteright Aring -72
-KPX quoteright comma -60
-KPX quoteright d -20
-KPX quoteright o -26
-KPX quoteright period -60
-KPX quoteright r -18
-KPX quoteright s -18
-KPX quoteright t -7
-KPX quoteright v -2
-KPX quoteright w 2
-KPX quoteright y -6
-KPX comma one -100
-KPX comma quotedblright -41
-KPX comma quoteright -50
-KPX hyphen A -7
-KPX hyphen AE -11
-KPX hyphen Aacute -7
-KPX hyphen Adieresis -7
-KPX hyphen Aring -7
-KPX hyphen T -80
-KPX hyphen V -46
-KPX hyphen W -19
-KPX hyphen Y -92
-KPX period one -101
-KPX period quotedblright -41
-KPX period quoteright -51
-KPX zero four -2
-KPX zero one -46
-KPX zero seven -39
-KPX one comma -74
-KPX one eight -65
-KPX one five -67
-KPX one four -81
-KPX one nine -65
-KPX one one -118
-KPX one period -74
-KPX one seven -90
-KPX one six -62
-KPX one three -67
-KPX one two -69
-KPX one zero -62
-KPX two four -37
-KPX two one -36
-KPX two seven -25
-KPX three four -2
-KPX three one -49
-KPX three seven -33
-KPX four four 5
-KPX four one -84
-KPX four seven -56
-KPX five four 1
-KPX five one -76
-KPX five seven -26
-KPX six four 1
-KPX six one -43
-KPX six seven -30
-KPX seven colon -77
-KPX seven comma -119
-KPX seven eight -28
-KPX seven five -30
-KPX seven four -93
-KPX seven one -53
-KPX seven period -119
-KPX seven seven -4
-KPX seven six -40
-KPX seven three -23
-KPX seven two -28
-KPX eight four 1
-KPX eight one -48
-KPX eight seven -33
-KPX nine four -3
-KPX nine one -43
-KPX nine seven -37
-KPX A C -36
-KPX A Ccedilla -36
-KPX A G -35
-KPX A O -33
-KPX A Odieresis -33
-KPX A Q -32
-KPX A T -93
-KPX A U -37
-KPX A Uacute -37
-KPX A Ucircumflex -37
-KPX A Udieresis -37
-KPX A Ugrave -37
-KPX A V -75
-KPX A W -51
-KPX A Y -99
-KPX A a -4
-KPX A b 4
-KPX A c -11
-KPX A ccedilla -10
-KPX A comma 5
-KPX A d -8
-KPX A e -16
-KPX A g -10
-KPX A guillemotleft -44
-KPX A guilsinglleft -40
-KPX A hyphen -3
-KPX A o -13
-KPX A period 5
-KPX A q -8
-KPX A quotedblright -56
-KPX A quoteright -65
-KPX A t -16
-KPX A u -12
-KPX A v -31
-KPX A w -21
-KPX A y -34
-KPX B A -21
-KPX B AE -21
-KPX B Aacute -21
-KPX B Acircumflex -21
-KPX B Adieresis -21
-KPX B Aring -21
-KPX B Atilde -21
-KPX B O -7
-KPX B OE -5
-KPX B Oacute -7
-KPX B Ocircumflex -7
-KPX B Odieresis -7
-KPX B Ograve -7
-KPX B Oslash -1
-KPX B V -41
-KPX B W -25
-KPX B Y -44
-KPX C A -32
-KPX C AE -33
-KPX C Aacute -32
-KPX C Adieresis -32
-KPX C Aring -32
-KPX C H -12
-KPX C K -10
-KPX C O -8
-KPX C Oacute -8
-KPX C Odieresis -8
-KPX D A -42
-KPX D Aacute -42
-KPX D Acircumflex -42
-KPX D Adieresis -42
-KPX D Agrave -42
-KPX D Aring -42
-KPX D Atilde -42
-KPX D J -5
-KPX D T -45
-KPX D V -51
-KPX D W -29
-KPX D X -53
-KPX D Y -63
-KPX F A -69
-KPX F Aacute -69
-KPX F Acircumflex -69
-KPX F Adieresis -69
-KPX F Agrave -69
-KPX F Aring -69
-KPX F Atilde -69
-KPX F J -51
-KPX F O -22
-KPX F Odieresis -22
-KPX F a -33
-KPX F aacute -33
-KPX F adieresis -33
-KPX F ae -29
-KPX F aring -33
-KPX F comma -108
-KPX F e -24
-KPX F eacute -24
-KPX F hyphen -14
-KPX F i -10
-KPX F j -12
-KPX F o -21
-KPX F oacute -21
-KPX F odieresis -21
-KPX F oe -23
-KPX F oslash -21
-KPX F period -108
-KPX F r -35
-KPX F u -33
-KPX G A -6
-KPX G AE -3
-KPX G Aacute -6
-KPX G Acircumflex -6
-KPX G Adieresis -6
-KPX G Agrave -6
-KPX G Aring -6
-KPX G Atilde -6
-KPX G T -44
-KPX G V -50
-KPX G W -28
-KPX G Y -62
-KPX J A -32
-KPX J AE -31
-KPX J Adieresis -32
-KPX J Aring -32
-KPX K C -51
-KPX K G -51
-KPX K O -48
-KPX K OE -45
-KPX K Oacute -48
-KPX K Odieresis -48
-KPX K S -38
-KPX K T 20
-KPX K a -11
-KPX K adieresis -11
-KPX K ae -7
-KPX K aring -11
-KPX K e -32
-KPX K hyphen -47
-KPX K o -29
-KPX K oacute -29
-KPX K odieresis -29
-KPX K u -19
-KPX K udieresis -19
-KPX K y -62
-KPX L A 17
-KPX L AE 20
-KPX L Aacute 17
-KPX L Adieresis 17
-KPX L Aring 17
-KPX L C -41
-KPX L Ccedilla -37
-KPX L G -42
-KPX L O -41
-KPX L Oacute -41
-KPX L Ocircumflex -41
-KPX L Odieresis -41
-KPX L Ograve -41
-KPX L Otilde -41
-KPX L S -19
-KPX L T -105
-KPX L U -35
-KPX L Udieresis -35
-KPX L V -105
-KPX L W -68
-KPX L Y -121
-KPX L hyphen -125
-KPX L quotedblright -141
-KPX L quoteright -149
-KPX L u -7
-KPX L udieresis -7
-KPX L y -56
-KPX N A -9
-KPX N AE -6
-KPX N Aacute -9
-KPX N Adieresis -9
-KPX N Aring -9
-KPX N C -3
-KPX N Ccedilla -3
-KPX N G -2
-KPX N a -5
-KPX N aacute -5
-KPX N adieresis -5
-KPX N ae -2
-KPX N aring -5
-KPX N comma -7
-KPX N o 2
-KPX N oacute 2
-KPX N odieresis 2
-KPX N oslash 4
-KPX N period -7
-KPX O A -35
-KPX O AE -39
-KPX O Aacute -35
-KPX O Adieresis -35
-KPX O Aring -35
-KPX O T -42
-KPX O V -45
-KPX O W -23
-KPX O X -46
-KPX O Y -59
-KPX P A -78
-KPX P AE -86
-KPX P Aacute -78
-KPX P Adieresis -78
-KPX P Aring -78
-KPX P J -78
-KPX P a -28
-KPX P aacute -28
-KPX P adieresis -28
-KPX P ae -24
-KPX P aring -28
-KPX P comma -135
-KPX P e -31
-KPX P eacute -31
-KPX P hyphen -40
-KPX P o -27
-KPX P oacute -27
-KPX P odieresis -27
-KPX P oe -28
-KPX P oslash -27
-KPX P period -135
-KPX R C -16
-KPX R Ccedilla -16
-KPX R G -15
-KPX R O -13
-KPX R OE -11
-KPX R Oacute -13
-KPX R Odieresis -13
-KPX R T -23
-KPX R U -17
-KPX R Udieresis -17
-KPX R V -39
-KPX R W -27
-KPX R Y -43
-KPX R a -15
-KPX R aacute -15
-KPX R adieresis -15
-KPX R ae -12
-KPX R aring -15
-KPX R e -12
-KPX R eacute -12
-KPX R hyphen -2
-KPX R o -9
-KPX R oacute -9
-KPX R odieresis -9
-KPX R oe -11
-KPX R u -9
-KPX R uacute -9
-KPX R udieresis -9
-KPX R y -8
-KPX S A -22
-KPX S AE -22
-KPX S Aacute -22
-KPX S Adieresis -22
-KPX S Aring -22
-KPX S T -28
-KPX S V -42
-KPX S W -28
-KPX S Y -48
-KPX S t -3
-KPX T A -95
-KPX T AE -97
-KPX T Aacute -95
-KPX T Acircumflex -95
-KPX T Adieresis -95
-KPX T Agrave -95
-KPX T Aring -95
-KPX T Atilde -95
-KPX T C -44
-KPX T G -45
-KPX T J -100
-KPX T O -42
-KPX T OE -35
-KPX T Oacute -42
-KPX T Ocircumflex -42
-KPX T Odieresis -42
-KPX T Ograve -42
-KPX T Oslash -41
-KPX T Otilde -42
-KPX T S -24
-KPX T V 12
-KPX T W 16
-KPX T Y 20
-KPX T a -100
-KPX T ae -97
-KPX T c -90
-KPX T colon -133
-KPX T comma -100
-KPX T e -95
-KPX T g -89
-KPX T guillemotleft -121
-KPX T guilsinglleft -117
-KPX T hyphen -77
-KPX T i -3
-KPX T j -5
-KPX T o -92
-KPX T oslash -87
-KPX T period -100
-KPX T r -92
-KPX T s -92
-KPX T semicolon -129
-KPX T u -91
-KPX T v -95
-KPX T w -93
-KPX T y -100
-KPX U A -36
-KPX U AE -39
-KPX U Aacute -36
-KPX U Acircumflex -36
-KPX U Adieresis -36
-KPX U Aring -36
-KPX U Atilde -36
-KPX U comma -27
-KPX U m -4
-KPX U n -4
-KPX U p 3
-KPX U period -25
-KPX U r -4
-KPX V A -71
-KPX V AE -78
-KPX V Aacute -71
-KPX V Acircumflex -71
-KPX V Adieresis -71
-KPX V Agrave -71
-KPX V Aring -71
-KPX V Atilde -71
-KPX V C -43
-KPX V G -42
-KPX V O -40
-KPX V Oacute -40
-KPX V Ocircumflex -40
-KPX V Odieresis -40
-KPX V Ograve -40
-KPX V Oslash -33
-KPX V Otilde -40
-KPX V S -35
-KPX V T 15
-KPX V a -59
-KPX V ae -55
-KPX V colon -66
-KPX V comma -89
-KPX V e -57
-KPX V g -50
-KPX V guillemotleft -83
-KPX V guilsinglleft -80
-KPX V hyphen -38
-KPX V i -5
-KPX V o -54
-KPX V oslash -50
-KPX V period -89
-KPX V r -42
-KPX V semicolon -66
-KPX V u -41
-KPX V y -20
-KPX W A -50
-KPX W AE -56
-KPX W Aacute -50
-KPX W Acircumflex -50
-KPX W Adieresis -50
-KPX W Agrave -50
-KPX W Aring -50
-KPX W Atilde -50
-KPX W C -23
-KPX W G -22
-KPX W O -20
-KPX W Oacute -20
-KPX W Ocircumflex -20
-KPX W Odieresis -20
-KPX W Ograve -20
-KPX W Oslash -13
-KPX W Otilde -20
-KPX W S -24
-KPX W T 19
-KPX W a -38
-KPX W ae -34
-KPX W colon -52
-KPX W comma -56
-KPX W e -32
-KPX W g -25
-KPX W guillemotleft -58
-KPX W guilsinglleft -54
-KPX W hyphen -13
-KPX W i -1
-KPX W o -29
-KPX W oslash -25
-KPX W period -56
-KPX W r -28
-KPX W semicolon -53
-KPX W u -28
-KPX W y -6
-KPX X C -48
-KPX X O -45
-KPX X Odieresis -45
-KPX X Q -44
-KPX X a -15
-KPX X e -36
-KPX X hyphen -51
-KPX X o -33
-KPX X u -24
-KPX X y -61
-KPX Y A -96
-KPX Y AE -103
-KPX Y Aacute -96
-KPX Y Acircumflex -96
-KPX Y Adieresis -96
-KPX Y Agrave -96
-KPX Y Aring -96
-KPX Y Atilde -96
-KPX Y C -58
-KPX Y G -58
-KPX Y O -56
-KPX Y Oacute -56
-KPX Y Ocircumflex -56
-KPX Y Odieresis -56
-KPX Y Ograve -56
-KPX Y Oslash -54
-KPX Y Otilde -56
-KPX Y S -41
-KPX Y T 23
-KPX Y a -88
-KPX Y ae -84
-KPX Y colon -87
-KPX Y comma -111
-KPX Y e -89
-KPX Y g -83
-KPX Y guillemotleft -123
-KPX Y guilsinglleft -119
-KPX Y hyphen -84
-KPX Y i 3
-KPX Y o -86
-KPX Y oslash -82
-KPX Y p -54
-KPX Y period -111
-KPX Y semicolon -88
-KPX Y u -63
-KPX Y v -36
-KPX Z v -33
-KPX Z y -38
-KPX quoteleft A -67
-KPX quoteleft AE -79
-KPX quoteleft Aacute -67
-KPX quoteleft Adieresis -67
-KPX quoteleft Aring -67
-KPX quoteleft T -5
-KPX quoteleft W 12
-KPX quoteleft Y -9
-KPX a j -4
-KPX a quoteright -23
-KPX a v -21
-KPX a w -13
-KPX a y -26
-KPX b v -11
-KPX b w -3
-KPX b y -15
-KPX c h 1
-KPX c k 7
-KPX e quoteright -18
-KPX e t -10
-KPX e v -15
-KPX e w -9
-KPX e x -27
-KPX e y -19
-KPX f a -9
-KPX f aacute -9
-KPX f adieresis -9
-KPX f ae -5
-KPX f aring -9
-KPX f e -15
-KPX f eacute -15
-KPX f f 22
-KPX f i -2
-KPX f j -4
-KPX f l -3
-KPX f o -10
-KPX f oacute -10
-KPX f odieresis -10
-KPX f oe -12
-KPX f oslash -9
-KPX f t 24
-KPX g a -5
-KPX g adieresis -5
-KPX g ae -1
-KPX g aring -5
-KPX g oacute 3
-KPX g odieresis 3
-KPX h quoteright -15
-KPX h y -18
-KPX i T -7
-KPX i j -3
-KPX k a -2
-KPX k aacute -2
-KPX k adieresis -2
-KPX k ae 2
-KPX k aring -2
-KPX k e -21
-KPX k eacute -21
-KPX k g -16
-KPX k hyphen -41
-KPX k o -19
-KPX k oacute -19
-KPX k odieresis -19
-KPX k s -3
-KPX k u -11
-KPX k udieresis -6
-KPX l y -5
-KPX m p 5
-KPX m v -13
-KPX m w -7
-KPX m y -18
-KPX n T -96
-KPX n p 5
-KPX n quoteright -14
-KPX n v -13
-KPX n w -7
-KPX n y -18
-KPX o T -99
-KPX o quoteright -21
-KPX o t -10
-KPX o v -18
-KPX o w -10
-KPX o x -27
-KPX o y -22
-KPX p t -4
-KPX p y -16
-KPX q c 8
-KPX q u 4
-KPX r a -5
-KPX r aacute -5
-KPX r acircumflex -5
-KPX r adieresis -5
-KPX r ae -1
-KPX r agrave -5
-KPX r aring -5
-KPX r c -6
-KPX r ccedilla -9
-KPX r colon -22
-KPX r comma -69
-KPX r d -1
-KPX r e -11
-KPX r eacute -11
-KPX r ecircumflex -11
-KPX r egrave -11
-KPX r f 26
-KPX r g -4
-KPX r hyphen -47
-KPX r i 1
-KPX r k 6
-KPX r l 1
-KPX r o -6
-KPX r oacute -6
-KPX r ocircumflex -6
-KPX r odieresis -6
-KPX r oe -8
-KPX r ograve -6
-KPX r oslash -6
-KPX r p 8
-KPX r period -69
-KPX r q -3
-KPX r quoteright 1
-KPX r s 4
-KPX r semicolon -22
-KPX r t 28
-KPX r u 2
-KPX r v 29
-KPX r w 31
-KPX r x 20
-KPX r y 24
-KPX r z 9
-KPX s quoteright -22
-KPX s t -3
-KPX t S -8
-KPX t a -1
-KPX t aacute -1
-KPX t adieresis -1
-KPX t ae 2
-KPX t aring -1
-KPX t colon -28
-KPX t e -14
-KPX t eacute -14
-KPX t h -3
-KPX t o -12
-KPX t oacute -12
-KPX t odieresis -12
-KPX t quoteright -1
-KPX t semicolon -28
-KPX u quoteright -8
-KPX v a -18
-KPX v aacute -18
-KPX v acircumflex -18
-KPX v adieresis -18
-KPX v ae -14
-KPX v agrave -18
-KPX v aring -18
-KPX v atilde -18
-KPX v c -16
-KPX v colon -23
-KPX v comma -69
-KPX v e -21
-KPX v eacute -21
-KPX v ecircumflex -21
-KPX v egrave -21
-KPX v g -14
-KPX v hyphen -12
-KPX v o -17
-KPX v oacute -17
-KPX v odieresis -17
-KPX v ograve -17
-KPX v oslash -17
-KPX v period -69
-KPX v s -9
-KPX v semicolon -23
-KPX w a -15
-KPX w aacute -15
-KPX w acircumflex -15
-KPX w adieresis -15
-KPX w ae -11
-KPX w agrave -15
-KPX w aring -15
-KPX w atilde -15
-KPX w c -7
-KPX w colon -23
-KPX w comma -50
-KPX w e -12
-KPX w eacute -12
-KPX w ecircumflex -12
-KPX w egrave -12
-KPX w g -6
-KPX w hyphen -1
-KPX w o -9
-KPX w oacute -9
-KPX w odieresis -9
-KPX w ograve -9
-KPX w oslash -6
-KPX w period -50
-KPX w s -5
-KPX w semicolon -23
-KPX x a -17
-KPX x c -23
-KPX x e -28
-KPX x eacute -28
-KPX x o -25
-KPX x q -20
-KPX y a -22
-KPX y aacute -22
-KPX y acircumflex -22
-KPX y adieresis -22
-KPX y ae -18
-KPX y agrave -22
-KPX y aring -22
-KPX y atilde -22
-KPX y c -19
-KPX y colon -27
-KPX y comma -70
-KPX y e -24
-KPX y eacute -24
-KPX y ecircumflex -24
-KPX y egrave -24
-KPX y g -17
-KPX y hyphen -14
-KPX y l -4
-KPX y o -20
-KPX y oacute -20
-KPX y odieresis -20
-KPX y ograve -20
-KPX y oslash -19
-KPX y period -70
-KPX y s -12
-KPX y semicolon -27
-KPX quotedblleft A -52
-KPX quotedblleft AE -64
-KPX quotedblleft Aacute -52
-KPX quotedblleft Adieresis -52
-KPX quotedblleft Aring -52
-KPX quotedblleft T 9
-KPX quotedblleft V 15
-KPX quotedblleft W 27
-KPX quotedblleft Y 5
-KPX guilsinglright A -44
-KPX guilsinglright AE -48
-KPX guilsinglright Aacute -44
-KPX guilsinglright Adieresis -44
-KPX guilsinglright Aring -44
-KPX guilsinglright T -121
-KPX guilsinglright V -88
-KPX guilsinglright W -60
-KPX guilsinglright Y -128
-KPX quotedblbase A 30
-KPX quotedblbase AE 30
-KPX quotedblbase T -75
-KPX quotedblbase V -69
-KPX quotedblbase W -34
-KPX quotedblbase Y -91
-KPX quotedblright A -53
-KPX quotedblright AE -66
-KPX quotedblright Aacute -53
-KPX quotedblright Adieresis -53
-KPX quotedblright Aring -53
-KPX quotedblright T 11
-KPX quotedblright V 15
-KPX quotedblright W 26
-KPX quotedblright Y 7
-KPX guillemotright A -50
-KPX guillemotright AE -54
-KPX guillemotright Aacute -50
-KPX guillemotright Adieresis -50
-KPX guillemotright Aring -50
-KPX guillemotright T -126
-KPX guillemotright V -93
-KPX guillemotright W -66
-KPX guillemotright Y -133
-KPX Oslash A -33
-KPX ae v -16
-KPX ae w -10
-KPX ae y -20
-KPX Adieresis C -36
-KPX Adieresis G -35
-KPX Adieresis O -33
-KPX Adieresis Q -32
-KPX Adieresis T -93
-KPX Adieresis U -37
-KPX Adieresis V -75
-KPX Adieresis W -51
-KPX Adieresis Y -99
-KPX Adieresis a -4
-KPX Adieresis b 4
-KPX Adieresis c -11
-KPX Adieresis comma 5
-KPX Adieresis d -8
-KPX Adieresis g -10
-KPX Adieresis guillemotleft -44
-KPX Adieresis guilsinglleft -40
-KPX Adieresis hyphen -3
-KPX Adieresis o -13
-KPX Adieresis period 5
-KPX Adieresis q -8
-KPX Adieresis quotedblright -56
-KPX Adieresis quoteright -65
-KPX Adieresis t -16
-KPX Adieresis u -12
-KPX Adieresis v -31
-KPX Adieresis w -21
-KPX Adieresis y -34
-KPX Aacute C -36
-KPX Aacute G -35
-KPX Aacute O -33
-KPX Aacute Q -32
-KPX Aacute T -93
-KPX Aacute U -37
-KPX Aacute V -75
-KPX Aacute W -51
-KPX Aacute Y -99
-KPX Aacute a -4
-KPX Aacute b 4
-KPX Aacute c -11
-KPX Aacute comma 5
-KPX Aacute d -8
-KPX Aacute e -16
-KPX Aacute g -10
-KPX Aacute guillemotleft -44
-KPX Aacute guilsinglleft -40
-KPX Aacute hyphen -3
-KPX Aacute o -13
-KPX Aacute period 5
-KPX Aacute q -8
-KPX Aacute quoteright -65
-KPX Aacute t -16
-KPX Aacute u -12
-KPX Aacute v -31
-KPX Aacute w -21
-KPX Aacute y -34
-KPX Agrave C -36
-KPX Agrave G -35
-KPX Agrave O -33
-KPX Agrave Q -32
-KPX Agrave T -93
-KPX Agrave U -37
-KPX Agrave V -75
-KPX Agrave W -51
-KPX Agrave Y -99
-KPX Agrave comma 5
-KPX Agrave period 5
-KPX Acircumflex C -36
-KPX Acircumflex G -35
-KPX Acircumflex O -33
-KPX Acircumflex Q -32
-KPX Acircumflex T -93
-KPX Acircumflex U -37
-KPX Acircumflex V -75
-KPX Acircumflex W -51
-KPX Acircumflex Y -99
-KPX Acircumflex comma 5
-KPX Acircumflex period 5
-KPX Atilde C -36
-KPX Atilde G -35
-KPX Atilde O -33
-KPX Atilde Q -32
-KPX Atilde T -93
-KPX Atilde U -37
-KPX Atilde V -75
-KPX Atilde W -51
-KPX Atilde Y -99
-KPX Atilde comma 5
-KPX Atilde period 5
-KPX Aring C -36
-KPX Aring G -35
-KPX Aring O -33
-KPX Aring Q -32
-KPX Aring T -93
-KPX Aring U -37
-KPX Aring V -75
-KPX Aring W -51
-KPX Aring Y -99
-KPX Aring a -4
-KPX Aring b 4
-KPX Aring c -11
-KPX Aring comma 5
-KPX Aring d -8
-KPX Aring e -16
-KPX Aring g -10
-KPX Aring guillemotleft -44
-KPX Aring guilsinglleft -40
-KPX Aring hyphen -3
-KPX Aring o -13
-KPX Aring period 5
-KPX Aring q -8
-KPX Aring quotedblright -56
-KPX Aring quoteright -65
-KPX Aring t -16
-KPX Aring u -12
-KPX Aring v -31
-KPX Aring w -21
-KPX Aring y -34
-KPX Ccedilla A -31
-KPX Odieresis A -35
-KPX Odieresis T -42
-KPX Odieresis V -45
-KPX Odieresis W -23
-KPX Odieresis X -46
-KPX Odieresis Y -59
-KPX Oacute A -35
-KPX Oacute T -42
-KPX Oacute V -45
-KPX Oacute W -23
-KPX Oacute Y -59
-KPX Ograve T -42
-KPX Ograve V -45
-KPX Ograve Y -59
-KPX Ocircumflex T -42
-KPX Ocircumflex V -45
-KPX Ocircumflex Y -59
-KPX Otilde T -42
-KPX Otilde V -45
-KPX Otilde Y -59
-KPX Udieresis A -36
-KPX Udieresis b 3
-KPX Udieresis comma -27
-KPX Udieresis m -4
-KPX Udieresis n -4
-KPX Udieresis p 3
-KPX Udieresis period -25
-KPX Udieresis r -4
-KPX Uacute A -36
-KPX Uacute comma -27
-KPX Uacute m -4
-KPX Uacute n -4
-KPX Uacute p 3
-KPX Uacute period -25
-KPX Uacute r -4
-KPX Ugrave A -36
-KPX Ucircumflex A -36
-KPX adieresis v -21
-KPX adieresis w -13
-KPX adieresis y -26
-KPX aacute v -21
-KPX aacute w -13
-KPX aacute y -26
-KPX agrave v -21
-KPX agrave w -13
-KPX agrave y -26
-KPX aring v -21
-KPX aring w -13
-KPX aring y -26
-KPX eacute v -15
-KPX eacute w -9
-KPX eacute y -19
-KPX ecircumflex v -15
-KPX ecircumflex w -9
-KPX ecircumflex y -19
-KPX odieresis t -10
-KPX odieresis v -18
-KPX odieresis w -10
-KPX odieresis x -27
-KPX odieresis y -22
-KPX oacute v -18
-KPX oacute w -10
-KPX oacute y -22
-KPX ograve v -18
-KPX ograve w -10
-KPX ograve y -22
-KPX ocircumflex t -10
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-sans-l/n019003l.pfb b/src/fonts/nimbus-sans-l/n019003l.pfb
deleted file mode 100644
index c2a9e86..0000000
--- a/src/fonts/nimbus-sans-l/n019003l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019003l.pfm b/src/fonts/nimbus-sans-l/n019003l.pfm
deleted file mode 100644
index 8a45fd3..0000000
--- a/src/fonts/nimbus-sans-l/n019003l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019004l.afm b/src/fonts/nimbus-sans-l/n019004l.afm
deleted file mode 100644
index fdae93d..0000000
--- a/src/fonts/nimbus-sans-l/n019004l.afm
+++ /dev/null
@@ -1,1561 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 14:36:28 2007
-FontName NimbusSanL-Bold
-FullName Nimbus Sans L Bold
-FamilyName Nimbus Sans L
-Weight Bold
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle 0
-IsFixedPitch false
-UnderlinePosition -155
-UnderlineThickness 69
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -173 -307 1097 979
-CapHeight 729
-XHeight 540
-Ascender 729
-Descender -218
-StartCharMetrics 562
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 112 0 262 726 ;
-C 34 ; WX 474 ; N quotedbl ; B 50 470 424 729 ;
-C 35 ; WX 556 ; N numbersign ; B 3 -32 553 697 ;
-C 36 ; WX 556 ; N dollar ; B 22 -126 527 763 ;
-C 37 ; WX 889 ; N percent ; B 22 -20 863 709 ;
-C 38 ; WX 722 ; N ampersand ; B 55 -23 694 723 ;
-C 39 ; WX 278 ; N quoteright ; B 66 469 201 729 ;
-C 40 ; WX 333 ; N parenleft ; B 40 -200 303 729 ;
-C 41 ; WX 333 ; N parenright ; B 22 -200 285 729 ;
-C 42 ; WX 389 ; N asterisk ; B 23 407 357 729 ;
-C 43 ; WX 584 ; N plus ; B 50 -10 533 473 ;
-C 44 ; WX 278 ; N comma ; B 64 -174 214 146 ;
-C 45 ; WX 333 ; N hyphen ; B 26 207 298 342 ;
-C 46 ; WX 278 ; N period ; B 64 0 214 146 ;
-C 47 ; WX 278 ; N slash ; B 2 -14 275 714 ;
-C 48 ; WX 556 ; N zero ; B 29 -23 517 724 ;
-C 49 ; WX 556 ; N one ; B 68 0 378 709 ;
-C 50 ; WX 556 ; N two ; B 30 0 515 724 ;
-C 51 ; WX 556 ; N three ; B 29 -23 516 724 ;
-C 52 ; WX 556 ; N four ; B 24 0 522 709 ;
-C 53 ; WX 556 ; N five ; B 27 -23 517 709 ;
-C 54 ; WX 556 ; N six ; B 32 -23 519 724 ;
-C 55 ; WX 556 ; N seven ; B 29 0 528 709 ;
-C 56 ; WX 556 ; N eight ; B 22 -23 525 724 ;
-C 57 ; WX 556 ; N nine ; B 28 -24 516 724 ;
-C 58 ; WX 333 ; N colon ; B 113 0 263 520 ;
-C 59 ; WX 333 ; N semicolon ; B 113 -174 263 520 ;
-C 60 ; WX 584 ; N less ; B 40 -10 529 474 ;
-C 61 ; WX 584 ; N equal ; B 50 52 534 411 ;
-C 62 ; WX 584 ; N greater ; B 40 -10 529 474 ;
-C 63 ; WX 611 ; N question ; B 64 0 556 744 ;
-C 64 ; WX 975 ; N at ; B 27 -138 947 745 ;
-C 65 ; WX 722 ; N A ; B 26 0 703 729 ;
-C 66 ; WX 722 ; N B ; B 82 0 666 729 ;
-C 67 ; WX 722 ; N C ; B 44 -23 685 741 ;
-C 68 ; WX 722 ; N D ; B 77 0 681 729 ;
-C 69 ; WX 667 ; N E ; B 79 0 624 729 ;
-C 70 ; WX 611 ; N F ; B 74 0 586 729 ;
-C 71 ; WX 778 ; N G ; B 42 -23 711 741 ;
-C 72 ; WX 722 ; N H ; B 68 0 657 729 ;
-C 73 ; WX 278 ; N I ; B 63 0 213 729 ; L J IJ ;
-C 74 ; WX 556 ; N J ; B 24 -23 486 729 ;
-C 75 ; WX 722 ; N K ; B 74 0 717 729 ;
-C 76 ; WX 611 ; N L ; B 80 0 579 729 ; L periodcentered Ldot ;
-C 77 ; WX 833 ; N M ; B 66 0 776 729 ;
-C 78 ; WX 722 ; N N ; B 68 0 661 729 ; L o afii61352 ;
-C 79 ; WX 778 ; N O ; B 40 -23 742 741 ;
-C 80 ; WX 667 ; N P ; B 76 0 633 729 ;
-C 81 ; WX 778 ; N Q ; B 43 -54 745 741 ;
-C 82 ; WX 722 ; N R ; B 80 0 677 729 ;
-C 83 ; WX 667 ; N S ; B 32 -23 633 741 ;
-C 84 ; WX 611 ; N T ; B 14 0 598 729 ; L M trademark ;
-C 85 ; WX 722 ; N U ; B 76 -23 654 729 ;
-C 86 ; WX 667 ; N V ; B 24 0 647 729 ;
-C 87 ; WX 944 ; N W ; B 13 0 932 729 ;
-C 88 ; WX 667 ; N X ; B 22 0 653 729 ;
-C 89 ; WX 667 ; N Y ; B 27 0 650 729 ;
-C 90 ; WX 611 ; N Z ; B 30 0 578 729 ;
-C 91 ; WX 333 ; N bracketleft ; B 66 -200 308 729 ;
-C 92 ; WX 278 ; N backslash ; B -12 -14 289 714 ;
-C 93 ; WX 333 ; N bracketright ; B 18 -200 260 729 ;
-C 94 ; WX 584 ; N asciicircum ; B 61 270 522 695 ;
-C 95 ; WX 556 ; N underscore ; B -22 -189 578 -120 ;
-C 96 ; WX 278 ; N quoteleft ; B 67 469 202 729 ;
-C 97 ; WX 556 ; N a ; B 28 -23 524 549 ;
-C 98 ; WX 611 ; N b ; B 59 -23 575 729 ;
-C 99 ; WX 556 ; N c ; B 34 -23 522 549 ;
-C 100 ; WX 611 ; N d ; B 29 -23 545 729 ;
-C 101 ; WX 556 ; N e ; B 22 -23 525 549 ;
-C 102 ; WX 333 ; N f ; B 14 0 313 729 ; L l fl ; L i fi ;
-C 103 ; WX 611 ; N g ; B 34 -218 541 549 ;
-C 104 ; WX 611 ; N h ; B 67 0 541 729 ;
-C 105 ; WX 278 ; N i ; B 67 0 207 729 ; L j ij ;
-C 106 ; WX 278 ; N j ; B 4 -218 210 729 ;
-C 107 ; WX 556 ; N k ; B 59 0 548 729 ;
-C 108 ; WX 278 ; N l ; B 67 0 207 729 ; L periodcentered ldot ;
-C 109 ; WX 889 ; N m ; B 60 0 824 549 ;
-C 110 ; WX 611 ; N n ; B 63 0 546 549 ;
-C 111 ; WX 611 ; N o ; B 35 -23 569 549 ;
-C 112 ; WX 611 ; N p ; B 58 -218 574 549 ;
-C 113 ; WX 611 ; N q ; B 28 -218 544 549 ;
-C 114 ; WX 389 ; N r ; B 63 0 370 549 ;
-C 115 ; WX 556 ; N s ; B 29 -23 520 549 ;
-C 116 ; WX 333 ; N t ; B 14 -23 301 674 ;
-C 117 ; WX 611 ; N u ; B 58 -23 541 540 ;
-C 118 ; WX 556 ; N v ; B 14 0 536 540 ;
-C 119 ; WX 778 ; N w ; B 5 0 766 540 ;
-C 120 ; WX 556 ; N x ; B 16 0 535 540 ;
-C 121 ; WX 556 ; N y ; B 9 -219 538 540 ;
-C 122 ; WX 500 ; N z ; B 21 0 468 540 ;
-C 123 ; WX 389 ; N braceleft ; B 37 -200 317 729 ;
-C 124 ; WX 280 ; N bar ; B 100 -200 180 729 ;
-C 125 ; WX 389 ; N braceright ; B 72 -200 352 729 ;
-C 126 ; WX 584 ; N asciitilde ; B 60 142 519 314 ;
-C 161 ; WX 333 ; N exclamdown ; B 66 -186 216 540 ;
-C 162 ; WX 556 ; N cent ; B 36 -124 522 634 ;
-C 163 ; WX 556 ; N sterling ; B 31 -23 537 715 ;
-C 164 ; WX 167 ; N fraction ; B -173 -20 337 715 ;
-C 165 ; WX 556 ; N yen ; B 5 0 552 704 ;
-C 166 ; WX 556 ; N florin ; B 21 -220 535 744 ;
-C 167 ; WX 556 ; N section ; B 33 -201 518 723 ;
-C 168 ; WX 556 ; N currency ; B 26 100 530 604 ;
-C 169 ; WX 238 ; N quotesingle ; B 50 470 188 729 ;
-C 170 ; WX 500 ; N quotedblleft ; B 71 469 433 729 ;
-C 171 ; WX 556 ; N guillemotleft ; B 88 72 468 481 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 83 72 250 481 ;
-C 173 ; WX 333 ; N guilsinglright ; B 80 72 247 481 ;
-C 174 ; WX 611 ; N fi ; B 9 0 548 729 ;
-C 175 ; WX 611 ; N fl ; B 12 0 546 729 ;
-C 177 ; WX 556 ; N endash ; B -9 207 557 311 ;
-C 178 ; WX 556 ; N dagger ; B 31 -194 523 709 ;
-C 179 ; WX 556 ; N daggerdbl ; B 28 -194 520 709 ;
-C 180 ; WX 278 ; N periodcentered ; B 64 169 188 292 ;
-C 182 ; WX 556 ; N paragraph ; B 19 -191 529 729 ;
-C 183 ; WX 350 ; N bullet ; B 50 175 300 425 ;
-C 184 ; WX 278 ; N quotesinglbase ; B 66 -135 201 125 ;
-C 185 ; WX 500 ; N quotedblbase ; B 72 -135 432 125 ;
-C 186 ; WX 500 ; N quotedblright ; B 73 469 440 729 ;
-C 187 ; WX 556 ; N guillemotright ; B 88 72 462 481 ;
-C 188 ; WX 1000 ; N ellipsis ; B 92 0 908 146 ;
-C 189 ; WX 1000 ; N perthousand ; B 11 -22 990 739 ;
-C 191 ; WX 611 ; N questiondown ; B 51 -204 544 540 ;
-C 193 ; WX 333 ; N grave ; B 17 607 213 757 ;
-C 194 ; WX 333 ; N acute ; B 121 607 317 757 ;
-C 195 ; WX 333 ; N circumflex ; B 8 607 326 757 ;
-C 196 ; WX 333 ; N tilde ; B -9 621 345 749 ;
-C 197 ; WX 333 ; N macron ; B 16 640 315 719 ;
-C 198 ; WX 333 ; N breve ; B 35 605 299 748 ;
-C 199 ; WX 333 ; N dotaccent ; B 112 621 222 743 ;
-C 200 ; WX 333 ; N dieresis ; B 18 621 314 743 ;
-C 202 ; WX 333 ; N ring ; B 77 590 257 770 ;
-C 203 ; WX 333 ; N cedilla ; B 27 -220 294 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B -44 610 340 757 ;
-C 206 ; WX 333 ; N ogonek ; B 45 -234 268 0 ;
-C 207 ; WX 333 ; N caron ; B 9 607 327 757 ;
-C 208 ; WX 1000 ; N emdash ; B -7 207 1003 311 ;
-C 225 ; WX 1000 ; N AE ; B 1 0 966 729 ;
-C 227 ; WX 370 ; N ordfeminine ; B 31 262 329 729 ;
-C 232 ; WX 611 ; N Lslash ; B 0 0 597 729 ;
-C 233 ; WX 778 ; N Oslash ; B 31 -39 755 749 ;
-C 234 ; WX 1000 ; N OE ; B 28 -23 970 741 ;
-C 235 ; WX 365 ; N ordmasculine ; B 23 262 343 729 ;
-C 241 ; WX 889 ; N ae ; B 27 -24 857 549 ;
-C 245 ; WX 278 ; N dotlessi ; B 67 0 207 540 ;
-C 248 ; WX 278 ; N lslash ; B 0 0 252 729 ;
-C 249 ; WX 611 ; N oslash ; B 11 -38 598 557 ;
-C 250 ; WX 944 ; N oe ; B 23 -23 920 549 ;
-C 251 ; WX 611 ; N germandbls ; B 67 -17 575 729 ;
-C -1 ; WX 722 ; N Adieresis ; B 26 0 703 922 ;
-C -1 ; WX 722 ; N Aacute ; B 26 0 703 936 ;
-C -1 ; WX 722 ; N Agrave ; B 26 0 703 936 ;
-C -1 ; WX 722 ; N Acircumflex ; B 26 0 703 936 ;
-C -1 ; WX 722 ; N Abreve ; B 26 0 703 927 ;
-C -1 ; WX 722 ; N Atilde ; B 26 0 703 928 ;
-C -1 ; WX 722 ; N Aring ; B 26 0 703 949 ;
-C -1 ; WX 722 ; N Aogonek ; B 26 -233 723 729 ;
-C -1 ; WX 722 ; N Ccedilla ; B 44 -220 685 741 ;
-C -1 ; WX 722 ; N Cacute ; B 44 -23 685 936 ;
-C -1 ; WX 722 ; N Ccaron ; B 44 -23 685 936 ;
-C -1 ; WX 722 ; N Dcaron ; B 77 0 681 936 ;
-C -1 ; WX 667 ; N Edieresis ; B 79 0 624 922 ;
-C -1 ; WX 667 ; N Eacute ; B 79 0 624 936 ;
-C -1 ; WX 667 ; N Egrave ; B 79 0 624 936 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 79 0 624 936 ;
-C -1 ; WX 667 ; N Ecaron ; B 79 0 624 936 ;
-C -1 ; WX 667 ; N Edotaccent ; B 79 0 624 922 ;
-C -1 ; WX 667 ; N Eogonek ; B 79 -233 648 729 ;
-C -1 ; WX 778 ; N Gbreve ; B 42 -23 711 927 ;
-C -1 ; WX 278 ; N Idieresis ; B -9 0 287 922 ;
-C -1 ; WX 278 ; N Iacute ; B 63 0 290 936 ;
-C -1 ; WX 278 ; N Igrave ; B -10 0 213 936 ;
-C -1 ; WX 278 ; N Icircumflex ; B -19 0 299 936 ;
-C -1 ; WX 278 ; N Idotaccent ; B 63 0 213 922 ;
-C -1 ; WX 611 ; N Lacute ; B 80 0 579 936 ;
-C -1 ; WX 611 ; N Lcaron ; B 80 0 579 729 ;
-C -1 ; WX 722 ; N Nacute ; B 68 0 661 936 ;
-C -1 ; WX 722 ; N Ncaron ; B 68 0 661 936 ;
-C -1 ; WX 722 ; N Ntilde ; B 68 0 661 928 ;
-C -1 ; WX 778 ; N Odieresis ; B 40 -23 742 922 ;
-C -1 ; WX 778 ; N Oacute ; B 40 -23 742 936 ;
-C -1 ; WX 778 ; N Ograve ; B 40 -23 742 936 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 40 -23 742 936 ;
-C -1 ; WX 778 ; N Otilde ; B 40 -23 742 928 ;
-C -1 ; WX 778 ; N Ohungarumlaut ; B 40 -23 742 936 ;
-C -1 ; WX 722 ; N Racute ; B 80 0 677 936 ;
-C -1 ; WX 722 ; N Rcaron ; B 80 0 677 936 ;
-C -1 ; WX 667 ; N Sacute ; B 32 -23 633 936 ;
-C -1 ; WX 667 ; N Scaron ; B 32 -23 633 936 ;
-C -1 ; WX 667 ; N Scedilla ; B 32 -220 633 741 ;
-C -1 ; WX 611 ; N Tcaron ; B 14 0 598 936 ;
-C -1 ; WX 722 ; N Udieresis ; B 76 -23 654 922 ;
-C -1 ; WX 722 ; N Uacute ; B 76 -23 654 936 ;
-C -1 ; WX 722 ; N Ugrave ; B 76 -23 654 936 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 76 -23 654 936 ;
-C -1 ; WX 722 ; N Uring ; B 76 -23 654 949 ;
-C -1 ; WX 722 ; N Uhungarumlaut ; B 76 -23 654 936 ;
-C -1 ; WX 667 ; N Yacute ; B 27 0 650 936 ;
-C -1 ; WX 611 ; N Zacute ; B 30 0 578 936 ;
-C -1 ; WX 611 ; N Zcaron ; B 30 0 578 936 ;
-C -1 ; WX 611 ; N Zdotaccent ; B 30 0 578 922 ;
-C -1 ; WX 722 ; N Amacron ; B 26 0 703 898 ;
-C -1 ; WX 611 ; N Tcommaaccent ; B 14 -307 598 729 ;
-C -1 ; WX 667 ; N Ydieresis ; B 27 0 650 922 ;
-C -1 ; WX 667 ; N Emacron ; B 79 0 624 898 ;
-C -1 ; WX 278 ; N Imacron ; B 2 0 274 898 ;
-C -1 ; WX 278 ; N Iogonek ; B 34 -233 237 729 ;
-C -1 ; WX 722 ; N Kcommaaccent ; B 74 -307 717 729 ;
-C -1 ; WX 611 ; N Lcommaaccent ; B 80 -307 579 729 ;
-C -1 ; WX 722 ; N Ncommaaccent ; B 68 -307 661 729 ;
-C -1 ; WX 778 ; N Omacron ; B 40 -23 742 898 ;
-C -1 ; WX 722 ; N Rcommaaccent ; B 80 -307 677 729 ;
-C -1 ; WX 778 ; N Gcommaaccent ; B 42 -307 711 741 ;
-C -1 ; WX 722 ; N Umacron ; B 76 -23 654 898 ;
-C -1 ; WX 722 ; N Uogonek ; B 76 -234 654 729 ;
-C -1 ; WX 556 ; N adieresis ; B 28 -23 524 743 ;
-C -1 ; WX 556 ; N aacute ; B 28 -23 524 757 ;
-C -1 ; WX 556 ; N agrave ; B 28 -23 524 757 ;
-C -1 ; WX 556 ; N acircumflex ; B 28 -23 524 757 ;
-C -1 ; WX 556 ; N abreve ; B 28 -23 524 748 ;
-C -1 ; WX 556 ; N atilde ; B 28 -23 524 749 ;
-C -1 ; WX 556 ; N aring ; B 28 -23 524 770 ;
-C -1 ; WX 556 ; N aogonek ; B 28 -233 548 549 ;
-C -1 ; WX 556 ; N cacute ; B 34 -23 522 757 ;
-C -1 ; WX 556 ; N ccaron ; B 34 -23 522 757 ;
-C -1 ; WX 556 ; N ccedilla ; B 34 -220 522 549 ;
-C -1 ; WX 707 ; N dcaron ; B 29 -23 720 729 ;
-C -1 ; WX 556 ; N edieresis ; B 22 -23 525 743 ;
-C -1 ; WX 556 ; N eacute ; B 22 -23 525 757 ;
-C -1 ; WX 556 ; N egrave ; B 22 -23 525 757 ;
-C -1 ; WX 556 ; N ecircumflex ; B 22 -23 525 757 ;
-C -1 ; WX 556 ; N ecaron ; B 22 -23 525 757 ;
-C -1 ; WX 556 ; N edotaccent ; B 22 -23 525 743 ;
-C -1 ; WX 556 ; N eogonek ; B 21 -234 525 549 ;
-C -1 ; WX 611 ; N gbreve ; B 34 -218 541 748 ;
-C -1 ; WX 278 ; N idieresis ; B -9 0 287 743 ;
-C -1 ; WX 278 ; N iacute ; B 67 0 290 757 ;
-C -1 ; WX 278 ; N igrave ; B -10 0 207 757 ;
-C -1 ; WX 278 ; N icircumflex ; B -19 0 299 757 ;
-C -1 ; WX 278 ; N lacute ; B 67 0 278 936 ;
-C -1 ; WX 369 ; N lcaron ; B 67 0 382 729 ;
-C -1 ; WX 611 ; N nacute ; B 63 0 546 757 ;
-C -1 ; WX 611 ; N ncaron ; B 63 0 546 757 ;
-C -1 ; WX 611 ; N ntilde ; B 63 0 546 749 ;
-C -1 ; WX 611 ; N odieresis ; B 35 -23 569 743 ;
-C -1 ; WX 611 ; N oacute ; B 35 -23 569 757 ;
-C -1 ; WX 611 ; N ograve ; B 35 -23 569 757 ;
-C -1 ; WX 611 ; N ocircumflex ; B 35 -23 569 757 ;
-C -1 ; WX 611 ; N otilde ; B 35 -23 569 749 ;
-C -1 ; WX 611 ; N ohungarumlaut ; B 35 -23 569 757 ;
-C -1 ; WX 389 ; N racute ; B 63 0 370 757 ;
-C -1 ; WX 556 ; N sacute ; B 29 -23 520 757 ;
-C -1 ; WX 556 ; N scaron ; B 29 -23 520 757 ;
-C -1 ; WX 556 ; N scommaaccent ; B 29 -307 520 549 ;
-C -1 ; WX 385 ; N tcaron ; B 14 -23 398 829 ;
-C -1 ; WX 611 ; N udieresis ; B 58 -23 541 743 ;
-C -1 ; WX 611 ; N uacute ; B 58 -23 541 757 ;
-C -1 ; WX 611 ; N ugrave ; B 58 -23 541 757 ;
-C -1 ; WX 611 ; N ucircumflex ; B 58 -23 541 757 ;
-C -1 ; WX 611 ; N uring ; B 58 -23 541 770 ;
-C -1 ; WX 611 ; N uhungarumlaut ; B 58 -23 559 757 ;
-C -1 ; WX 556 ; N yacute ; B 9 -219 538 757 ;
-C -1 ; WX 500 ; N zacute ; B 21 0 468 757 ;
-C -1 ; WX 500 ; N zcaron ; B 21 0 468 757 ;
-C -1 ; WX 500 ; N zdotaccent ; B 21 0 468 743 ;
-C -1 ; WX 556 ; N ydieresis ; B 9 -219 538 743 ;
-C -1 ; WX 333 ; N tcommaaccent ; B 14 -307 301 674 ;
-C -1 ; WX 556 ; N amacron ; B 28 -23 524 719 ;
-C -1 ; WX 556 ; N emacron ; B 22 -23 525 719 ;
-C -1 ; WX 278 ; N imacron ; B 7 0 266 719 ;
-C -1 ; WX 556 ; N kcommaaccent ; B 59 -307 548 729 ;
-C -1 ; WX 278 ; N lcommaaccent ; B 67 -307 207 729 ;
-C -1 ; WX 611 ; N ncommaaccent ; B 63 -307 546 549 ;
-C -1 ; WX 611 ; N omacron ; B 35 -23 569 719 ;
-C -1 ; WX 389 ; N rcommaaccent ; B 63 -307 370 549 ;
-C -1 ; WX 611 ; N umacron ; B 58 -23 541 719 ;
-C -1 ; WX 611 ; N uogonek ; B 58 -233 564 540 ;
-C -1 ; WX 389 ; N rcaron ; B 54 0 372 757 ;
-C -1 ; WX 556 ; N scedilla ; B 29 -220 520 549 ;
-C -1 ; WX 611 ; N gcommaaccent ; B 34 -218 541 853 ;
-C -1 ; WX 278 ; N iogonek ; B 34 -233 231 729 ;
-C -1 ; WX 667 ; N Scommaaccent ; B 32 -307 633 741 ;
-C -1 ; WX 722 ; N Eth ; B 0 0 681 729 ;
-C -1 ; WX 722 ; N Dcroat ; B 0 0 681 729 ;
-C -1 ; WX 667 ; N Thorn ; B 76 0 633 729 ;
-C -1 ; WX 611 ; N dcroat ; B 29 -23 605 729 ;
-C -1 ; WX 611 ; N eth ; B 35 -23 569 744 ;
-C -1 ; WX 611 ; N thorn ; B 58 -218 574 729 ;
-C -1 ; WX 556 ; N Euro ; B 6 -23 546 724 ;
-C -1 ; WX 351 ; N onesuperior ; B 40 284 242 709 ;
-C -1 ; WX 351 ; N twosuperior ; B 16 284 328 718 ;
-C -1 ; WX 351 ; N threesuperior ; B 15 271 329 718 ;
-C -1 ; WX 606 ; N degree ; B 151 383 454 686 ;
-C -1 ; WX 584 ; N minus ; B 40 172 544 291 ;
-C -1 ; WX 584 ; N multiply ; B 79 18 505 444 ;
-C -1 ; WX 584 ; N divide ; B 50 -11 534 474 ;
-C -1 ; WX 1000 ; N trademark ; B 71 273 929 729 ;
-C -1 ; WX 584 ; N plusminus ; B 56 -16 527 608 ;
-C -1 ; WX 869 ; N onehalf ; B 40 -20 846 715 ;
-C -1 ; WX 869 ; N onequarter ; B 40 -20 850 715 ;
-C -1 ; WX 869 ; N threequarters ; B 15 -20 850 718 ;
-C -1 ; WX 333 ; N commaaccent ; B 112 -307 234 -60 ;
-C -1 ; WX 737 ; N copyright ; B -14 -22 751 743 ;
-C -1 ; WX 737 ; N registered ; B -14 -22 751 743 ;
-C -1 ; WX 489 ; N lozenge ; B 16 0 462 744 ;
-C -1 ; WX 729 ; N Delta ; B 8 0 721 729 ;
-C -1 ; WX 548 ; N notequal ; B 50 -69 534 528 ;
-C -1 ; WX 542 ; N radical ; B 7 -36 512 913 ;
-C -1 ; WX 584 ; N lessequal ; B 45 -10 534 639 ;
-C -1 ; WX 584 ; N greaterequal ; B 45 -10 534 639 ;
-C -1 ; WX 584 ; N logicalnot ; B 40 86 544 375 ;
-C -1 ; WX 711 ; N summation ; B 17 -96 694 760 ;
-C -1 ; WX 490 ; N partialdiff ; B 22 -15 458 750 ;
-C -1 ; WX 280 ; N brokenbar ; B 100 -200 180 729 ;
-C -1 ; WX 611 ; N mu ; B 58 -220 573 540 ;
-C -1 ; WX 722 ; N afii10017 ; B 26 0 703 729 ;
-C -1 ; WX 722 ; N afii10018 ; B 82 0 666 729 ;
-C -1 ; WX 722 ; N afii10019 ; B 82 0 666 729 ;
-C -1 ; WX 611 ; N afii10020 ; B 82 0 594 729 ;
-C -1 ; WX 900 ; N afii10021 ; B 35 -150 865 729 ;
-C -1 ; WX 709 ; N afii10022 ; B 82 0 627 729 ;
-C -1 ; WX 709 ; N afii10023 ; B 82 0 627 922 ;
-C -1 ; WX 1093 ; N afii10024 ; B 22 0 1078 729 ;
-C -1 ; WX 672 ; N afii10025 ; B 32 -23 633 741 ;
-C -1 ; WX 757 ; N afii10026 ; B 82 0 675 729 ;
-C -1 ; WX 757 ; N afii10027 ; B 82 0 675 927 ;
-C -1 ; WX 750 ; N afii10028 ; B 82 0 725 729 ;
-C -1 ; WX 729 ; N afii10029 ; B 36 -12 647 729 ;
-C -1 ; WX 874 ; N afii10030 ; B 82 0 792 729 ;
-C -1 ; WX 753 ; N afii10031 ; B 82 0 671 729 ;
-C -1 ; WX 778 ; N afii10032 ; B 40 -23 742 741 ;
-C -1 ; WX 753 ; N afii10033 ; B 82 0 671 729 ;
-C -1 ; WX 671 ; N afii10034 ; B 82 0 639 729 ;
-C -1 ; WX 722 ; N afii10035 ; B 44 -23 685 741 ;
-C -1 ; WX 611 ; N afii10036 ; B 14 0 598 729 ;
-C -1 ; WX 718 ; N afii10037 ; B 15 0 696 729 ;
-C -1 ; WX 892 ; N afii10038 ; B 30 0 862 729 ;
-C -1 ; WX 667 ; N afii10039 ; B 22 0 654 729 ;
-C -1 ; WX 816 ; N afii10040 ; B 82 -150 781 729 ;
-C -1 ; WX 685 ; N afii10041 ; B 68 0 624 729 ;
-C -1 ; WX 1057 ; N afii10042 ; B 68 0 967 729 ;
-C -1 ; WX 1183 ; N afii10043 ; B 68 -150 1097 729 ;
-C -1 ; WX 833 ; N afii10044 ; B 14 0 801 729 ;
-C -1 ; WX 949 ; N afii10045 ; B 68 0 884 729 ;
-C -1 ; WX 687 ; N afii10046 ; B 76 0 633 729 ;
-C -1 ; WX 722 ; N afii10047 ; B 44 -23 685 741 ;
-C -1 ; WX 1099 ; N afii10048 ; B 68 -23 1033 741 ;
-C -1 ; WX 698 ; N afii10049 ; B 22 0 633 729 ;
-C -1 ; WX 556 ; N afii10065 ; B 28 -23 524 549 ;
-C -1 ; WX 606 ; N afii10066 ; B 50 -23 565 777 ;
-C -1 ; WX 572 ; N afii10067 ; B 60 0 518 540 ;
-C -1 ; WX 454 ; N afii10068 ; B 60 0 408 540 ;
-C -1 ; WX 685 ; N afii10069 ; B 23 -125 662 540 ;
-C -1 ; WX 556 ; N afii10070 ; B 22 -23 525 549 ;
-C -1 ; WX 556 ; N afii10071 ; B 22 -23 525 743 ;
-C -1 ; WX 809 ; N afii10072 ; B 16 0 788 540 ;
-C -1 ; WX 546 ; N afii10073 ; B 29 -23 520 549 ;
-C -1 ; WX 615 ; N afii10074 ; B 60 0 555 540 ;
-C -1 ; WX 615 ; N afii10075 ; B 60 0 555 723 ;
-C -1 ; WX 573 ; N afii10076 ; B 60 0 549 540 ;
-C -1 ; WX 577 ; N afii10077 ; B 29 -10 517 540 ;
-C -1 ; WX 666 ; N afii10078 ; B 60 0 606 540 ;
-C -1 ; WX 603 ; N afii10079 ; B 60 0 543 540 ;
-C -1 ; WX 611 ; N afii10080 ; B 35 -23 569 549 ;
-C -1 ; WX 603 ; N afii10081 ; B 60 0 543 540 ;
-C -1 ; WX 611 ; N afii10082 ; B 58 -218 574 549 ;
-C -1 ; WX 556 ; N afii10083 ; B 34 -23 522 549 ;
-C -1 ; WX 454 ; N afii10084 ; B 21 0 431 540 ;
-C -1 ; WX 556 ; N afii10085 ; B 9 -219 538 540 ;
-C -1 ; WX 957 ; N afii10086 ; B 28 -218 920 719 ;
-C -1 ; WX 556 ; N afii10087 ; B 16 0 535 540 ;
-C -1 ; WX 652 ; N afii10088 ; B 60 -125 629 540 ;
-C -1 ; WX 578 ; N afii10089 ; B 60 0 518 540 ;
-C -1 ; WX 886 ; N afii10090 ; B 60 0 826 540 ;
-C -1 ; WX 968 ; N afii10091 ; B 60 -125 945 540 ;
-C -1 ; WX 693 ; N afii10092 ; B 20 0 663 540 ;
-C -1 ; WX 811 ; N afii10093 ; B 60 0 718 540 ;
-C -1 ; WX 562 ; N afii10094 ; B 60 0 532 540 ;
-C -1 ; WX 564 ; N afii10095 ; B 34 -23 522 549 ;
-C -1 ; WX 888 ; N afii10096 ; B 60 -23 792 549 ;
-C -1 ; WX 596 ; N afii10097 ; B 25 0 531 540 ;
-C -1 ; WX 709 ; N uni0400 ; B 82 0 627 951 ;
-C -1 ; WX 769 ; N afii10051 ; B 14 -172 720 729 ;
-C -1 ; WX 611 ; N afii10052 ; B 82 0 594 951 ;
-C -1 ; WX 722 ; N afii10053 ; B 44 -23 685 741 ;
-C -1 ; WX 667 ; N afii10054 ; B 32 -23 633 741 ;
-C -1 ; WX 278 ; N afii10055 ; B 63 0 213 729 ;
-C -1 ; WX 278 ; N afii10056 ; B -9 0 287 922 ;
-C -1 ; WX 556 ; N afii10057 ; B 24 -23 486 729 ;
-C -1 ; WX 1106 ; N afii10058 ; B 46 0 1064 729 ;
-C -1 ; WX 1113 ; N afii10059 ; B 68 0 1064 729 ;
-C -1 ; WX 769 ; N afii10060 ; B 14 0 720 729 ;
-C -1 ; WX 750 ; N afii10061 ; B 82 0 725 951 ;
-C -1 ; WX 757 ; N uni040D ; B 82 0 675 951 ;
-C -1 ; WX 718 ; N afii10062 ; B 15 0 696 944 ;
-C -1 ; WX 722 ; N afii10145 ; B 68 -150 658 729 ;
-C -1 ; WX 556 ; N uni0450 ; B 22 -23 525 759 ;
-C -1 ; WX 611 ; N afii10099 ; B 12 -187 541 729 ;
-C -1 ; WX 454 ; N afii10100 ; B 60 0 408 759 ;
-C -1 ; WX 556 ; N afii10101 ; B 34 -23 522 549 ;
-C -1 ; WX 556 ; N afii10102 ; B 29 -23 520 549 ;
-C -1 ; WX 278 ; N afii10103 ; B 67 0 207 729 ;
-C -1 ; WX 278 ; N afii10104 ; B -9 0 287 743 ;
-C -1 ; WX 278 ; N afii10105 ; B 4 -218 210 729 ;
-C -1 ; WX 923 ; N afii10106 ; B 29 0 875 540 ;
-C -1 ; WX 903 ; N afii10107 ; B 63 0 878 540 ;
-C -1 ; WX 611 ; N afii10108 ; B 12 0 541 729 ;
-C -1 ; WX 573 ; N afii10109 ; B 60 0 549 759 ;
-C -1 ; WX 615 ; N uni045D ; B 60 0 555 759 ;
-C -1 ; WX 556 ; N afii10110 ; B 9 -219 538 752 ;
-C -1 ; WX 608 ; N afii10193 ; B 60 -125 544 540 ;
-C -1 ; WX 687 ; N uni048C ; B 6 0 633 729 ;
-C -1 ; WX 562 ; N uni048D ; B -20 0 540 540 ;
-C -1 ; WX 667 ; N uni048E ; B 76 0 633 729 ;
-C -1 ; WX 611 ; N uni048F ; B 58 -218 574 549 ;
-C -1 ; WX 611 ; N afii10050 ; B 74 0 586 864 ;
-C -1 ; WX 454 ; N afii10098 ; B 64 0 412 666 ;
-C -1 ; WX 611 ; N uni0492 ; B 4 0 594 729 ;
-C -1 ; WX 454 ; N uni0493 ; B -6 0 408 540 ;
-C -1 ; WX 611 ; N uni0494 ; B 74 -172 599 729 ;
-C -1 ; WX 584 ; N uni0495 ; B 60 -187 534 540 ;
-C -1 ; WX 1093 ; N uni0496 ; B 22 -150 1078 729 ;
-C -1 ; WX 809 ; N uni0497 ; B 16 -125 788 540 ;
-C -1 ; WX 672 ; N uni0498 ; B 32 -234 633 741 ;
-C -1 ; WX 546 ; N uni0499 ; B 29 -234 520 549 ;
-C -1 ; WX 750 ; N uni049A ; B 82 -150 725 729 ;
-C -1 ; WX 573 ; N uni049B ; B 60 -125 549 540 ;
-C -1 ; WX 722 ; N uni049C ; B 82 0 725 729 ;
-C -1 ; WX 573 ; N uni049D ; B 60 0 549 540 ;
-C -1 ; WX 722 ; N uni049E ; B 2 0 724 729 ;
-C -1 ; WX 573 ; N uni049F ; B 8 0 548 540 ;
-C -1 ; WX 912 ; N uni04A0 ; B 14 0 887 729 ;
-C -1 ; WX 704 ; N uni04A1 ; B 20 0 680 540 ;
-C -1 ; WX 753 ; N uni04A2 ; B 82 -150 791 729 ;
-C -1 ; WX 608 ; N uni04A3 ; B 60 -125 629 540 ;
-C -1 ; WX 985 ; N uni04A4 ; B 68 0 968 729 ;
-C -1 ; WX 787 ; N uni04A5 ; B 60 0 741 540 ;
-C -1 ; WX 1092 ; N uni04A6 ; B 68 -172 1032 729 ;
-C -1 ; WX 925 ; N uni04A7 ; B 60 -187 877 540 ;
-C -1 ; WX 722 ; N uni04A8 ; B 44 -23 713 741 ;
-C -1 ; WX 556 ; N uni04A9 ; B 34 -27 536 549 ;
-C -1 ; WX 722 ; N uni04AA ; B 44 -234 685 741 ;
-C -1 ; WX 556 ; N uni04AB ; B 34 -234 522 549 ;
-C -1 ; WX 611 ; N uni04AC ; B 14 -150 598 729 ;
-C -1 ; WX 454 ; N uni04AD ; B 21 -125 431 540 ;
-C -1 ; WX 667 ; N uni04AE ; B 27 0 650 729 ;
-C -1 ; WX 667 ; N uni04AF ; B 57 -189 620 540 ;
-C -1 ; WX 667 ; N uni04B0 ; B 27 0 650 729 ;
-C -1 ; WX 667 ; N uni04B1 ; B 57 -189 620 540 ;
-C -1 ; WX 667 ; N uni04B2 ; B 22 -150 653 729 ;
-C -1 ; WX 556 ; N uni04B3 ; B 16 -125 535 540 ;
-C -1 ; WX 951 ; N uni04B4 ; B 14 -150 904 729 ;
-C -1 ; WX 738 ; N uni04B5 ; B 21 -125 715 540 ;
-C -1 ; WX 781 ; N uni04B6 ; B 68 -150 734 729 ;
-C -1 ; WX 627 ; N uni04B7 ; B 60 -125 604 540 ;
-C -1 ; WX 685 ; N uni04B8 ; B 68 0 624 729 ;
-C -1 ; WX 578 ; N uni04B9 ; B 60 0 518 540 ;
-C -1 ; WX 685 ; N uni04BA ; B 68 0 624 729 ;
-C -1 ; WX 578 ; N uni04BB ; B 60 0 518 540 ;
-C -1 ; WX 957 ; N uni04BC ; B 25 -23 920 745 ;
-C -1 ; WX 716 ; N uni04BD ; B 20 -23 682 549 ;
-C -1 ; WX 957 ; N uni04BE ; B 25 -234 920 745 ;
-C -1 ; WX 716 ; N uni04BF ; B 20 -234 682 549 ;
-C -1 ; WX 278 ; N uni04C0 ; B 63 0 213 729 ;
-C -1 ; WX 1093 ; N uni04C1 ; B 22 0 1078 944 ;
-C -1 ; WX 809 ; N uni04C2 ; B 16 0 788 752 ;
-C -1 ; WX 750 ; N uni04C3 ; B 82 -172 694 729 ;
-C -1 ; WX 573 ; N uni04C4 ; B 60 -188 510 540 ;
-C -1 ; WX 722 ; N uni04C7 ; B 68 -172 657 729 ;
-C -1 ; WX 608 ; N uni04C8 ; B 60 -187 543 540 ;
-C -1 ; WX 685 ; N uni04CB ; B 68 -150 624 729 ;
-C -1 ; WX 578 ; N uni04CC ; B 60 -125 518 540 ;
-C -1 ; WX 722 ; N uni04D0 ; B 26 0 703 944 ;
-C -1 ; WX 556 ; N uni04D1 ; B 28 -23 524 752 ;
-C -1 ; WX 722 ; N uni04D2 ; B 26 0 703 923 ;
-C -1 ; WX 556 ; N uni04D3 ; B 28 -23 524 731 ;
-C -1 ; WX 1000 ; N uni04D4 ; B 1 0 966 729 ;
-C -1 ; WX 889 ; N uni04D5 ; B 27 -24 857 549 ;
-C -1 ; WX 709 ; N uni04D6 ; B 82 0 627 944 ;
-C -1 ; WX 556 ; N uni04D7 ; B 22 -23 525 752 ;
-C -1 ; WX 722 ; N uni04D8 ; B 44 -23 685 741 ;
-C -1 ; WX 556 ; N afii10846 ; B 34 -23 522 549 ;
-C -1 ; WX 722 ; N uni04DA ; B 44 -23 685 923 ;
-C -1 ; WX 556 ; N uni04DB ; B 34 -23 522 731 ;
-C -1 ; WX 1093 ; N uni04DC ; B 22 0 1078 923 ;
-C -1 ; WX 809 ; N uni04DD ; B 16 0 788 731 ;
-C -1 ; WX 672 ; N uni04DE ; B 32 -23 633 923 ;
-C -1 ; WX 546 ; N uni04DF ; B 29 -23 520 731 ;
-C -1 ; WX 672 ; N uni04E0 ; B 32 -23 634 729 ;
-C -1 ; WX 546 ; N uni04E1 ; B 29 -23 520 540 ;
-C -1 ; WX 757 ; N uni04E2 ; B 82 0 675 880 ;
-C -1 ; WX 615 ; N uni04E3 ; B 60 0 555 688 ;
-C -1 ; WX 757 ; N uni04E4 ; B 82 0 675 923 ;
-C -1 ; WX 615 ; N uni04E5 ; B 60 0 555 731 ;
-C -1 ; WX 778 ; N uni04E6 ; B 40 -23 742 923 ;
-C -1 ; WX 611 ; N uni04E7 ; B 35 -23 569 731 ;
-C -1 ; WX 778 ; N uni04E8 ; B 40 -23 742 741 ;
-C -1 ; WX 611 ; N uni04E9 ; B 35 -23 569 549 ;
-C -1 ; WX 778 ; N uni04EA ; B 40 -23 742 923 ;
-C -1 ; WX 611 ; N uni04EB ; B 35 -23 569 731 ;
-C -1 ; WX 722 ; N uni04EC ; B 44 -23 685 923 ;
-C -1 ; WX 564 ; N uni04ED ; B 34 -23 522 731 ;
-C -1 ; WX 718 ; N uni04EE ; B 15 0 696 880 ;
-C -1 ; WX 556 ; N uni04EF ; B 9 -219 538 688 ;
-C -1 ; WX 718 ; N uni04F0 ; B 15 0 696 923 ;
-C -1 ; WX 556 ; N uni04F1 ; B 9 -219 538 731 ;
-C -1 ; WX 718 ; N uni04F2 ; B 15 0 696 948 ;
-C -1 ; WX 556 ; N uni04F3 ; B 9 -219 538 756 ;
-C -1 ; WX 685 ; N uni04F4 ; B 68 0 624 923 ;
-C -1 ; WX 578 ; N uni04F5 ; B 60 0 518 731 ;
-C -1 ; WX 949 ; N uni04F8 ; B 68 0 884 923 ;
-C -1 ; WX 811 ; N uni04F9 ; B 60 0 718 731 ;
-C -1 ; WX 454 ; N uniF6C4 ; B 60 0 408 540 ;
-C -1 ; WX 611 ; N uniF6C5 ; B 110 -23 625 777 ;
-C -1 ; WX 685 ; N uniF6C6 ; B 23 -125 662 540 ;
-C -1 ; WX 603 ; N uniF6C7 ; B 60 0 543 540 ;
-C -1 ; WX 454 ; N uniF6C8 ; B 21 0 431 540 ;
-C -1 ; WX 722 ; N Ccircumflex ; B 44 -23 685 979 ;
-C -1 ; WX 556 ; N ccircumflex ; B 34 -23 522 790 ;
-C -1 ; WX 722 ; N Cdotaccent ; B 44 -23 685 951 ;
-C -1 ; WX 556 ; N cdotaccent ; B 34 -23 522 762 ;
-C -1 ; WX 667 ; N Ebreve ; B 79 0 624 972 ;
-C -1 ; WX 556 ; N ebreve ; B 22 -23 525 783 ;
-C -1 ; WX 778 ; N Gcircumflex ; B 42 -23 711 979 ;
-C -1 ; WX 611 ; N gcircumflex ; B 34 -218 541 790 ;
-C -1 ; WX 778 ; N Gdotaccent ; B 42 -23 711 951 ;
-C -1 ; WX 611 ; N gdotaccent ; B 34 -218 541 762 ;
-C -1 ; WX 722 ; N Hcircumflex ; B 68 0 657 979 ;
-C -1 ; WX 611 ; N hcircumflex ; B 67 0 541 979 ;
-C -1 ; WX 752 ; N Hbar ; B 26 0 726 729 ;
-C -1 ; WX 611 ; N hbar ; B 16 0 541 729 ;
-C -1 ; WX 278 ; N Itilde ; B -39 0 315 957 ;
-C -1 ; WX 278 ; N itilde ; B -40 0 314 768 ;
-C -1 ; WX 278 ; N Ibreve ; B 6 0 270 972 ;
-C -1 ; WX 278 ; N ibreve ; B 5 0 269 783 ;
-C -1 ; WX 808 ; N IJ ; B 63 -23 740 729 ;
-C -1 ; WX 492 ; N ij ; B 67 -218 418 729 ;
-C -1 ; WX 556 ; N Jcircumflex ; B 24 -23 570 979 ;
-C -1 ; WX 278 ; N jcircumflex ; B -19 -218 299 783 ;
-C -1 ; WX 573 ; N kgreenlandic ; B 59 0 548 540 ;
-C -1 ; WX 611 ; N Ldot ; B 80 0 579 729 ;
-C -1 ; WX 556 ; N ldot ; B 67 0 444 729 ;
-C -1 ; WX 611 ; N napostrophe ; B 63 0 546 849 ;
-C -1 ; WX 722 ; N Eng ; B 68 -172 661 729 ;
-C -1 ; WX 611 ; N eng ; B 63 -187 546 549 ;
-C -1 ; WX 778 ; N Obreve ; B 40 -23 742 972 ;
-C -1 ; WX 611 ; N obreve ; B 35 -23 569 783 ;
-C -1 ; WX 667 ; N Scircumflex ; B 32 -23 633 979 ;
-C -1 ; WX 556 ; N scircumflex ; B 29 -23 520 790 ;
-C -1 ; WX 611 ; N Tbar ; B 14 0 598 729 ;
-C -1 ; WX 333 ; N tbar ; B 14 -23 302 674 ;
-C -1 ; WX 722 ; N Utilde ; B 76 -23 654 957 ;
-C -1 ; WX 611 ; N utilde ; B 58 -23 541 768 ;
-C -1 ; WX 722 ; N Ubreve ; B 76 -23 654 972 ;
-C -1 ; WX 611 ; N ubreve ; B 58 -23 541 783 ;
-C -1 ; WX 944 ; N Wcircumflex ; B 13 0 932 979 ;
-C -1 ; WX 778 ; N wcircumflex ; B 5 0 766 790 ;
-C -1 ; WX 667 ; N Ycircumflex ; B 27 0 650 979 ;
-C -1 ; WX 556 ; N ycircumflex ; B 9 -219 538 790 ;
-C -1 ; WX 333 ; N longs ; B 14 0 308 729 ;
-C -1 ; WX 1082 ; N afii61352 ; B 68 0 1026 729 ;
-C -1 ; WX 871 ; N infinity ; B 29 109 847 592 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 973
-KPX quoteright y -3
-KPX quoteright w 1
-KPX quoteright v -5
-KPX quoteright t -4
-KPX quoteright s -22
-KPX quoteright r -15
-KPX quoteright period -45
-KPX quoteright o -30
-KPX quoteright d -27
-KPX quoteright comma -46
-KPX quoteright Aring -77
-KPX quoteright Adieresis -77
-KPX quoteright Aacute -77
-KPX quoteright AE -66
-KPX quoteright A -77
-KPX comma quoteright -30
-KPX comma quotedblright -33
-KPX comma one -73
-KPX hyphen Y -64
-KPX hyphen W -9
-KPX hyphen V -27
-KPX hyphen T -57
-KPX hyphen Aring -1
-KPX hyphen Adieresis -1
-KPX hyphen Aacute -1
-KPX hyphen AE 10
-KPX hyphen A -1
-KPX period quoteright -29
-KPX period quotedblright -32
-KPX period one -73
-KPX zero seven -10
-KPX zero one -19
-KPX zero four 5
-KPX one zero -34
-KPX one two -47
-KPX one three -44
-KPX one six -37
-KPX one seven -65
-KPX one period -42
-KPX one one -85
-KPX one nine -39
-KPX one four -56
-KPX one five -43
-KPX one eight -37
-KPX one comma -42
-KPX two seven -3
-KPX two one -16
-KPX two four -9
-KPX three seven -10
-KPX three one -27
-KPX three four 6
-KPX four seven -28
-KPX four one -50
-KPX four four 9
-KPX five seven -10
-KPX five one -29
-KPX five four 6
-KPX six seven -3
-KPX six one -21
-KPX six four 7
-KPX seven two -4
-KPX seven six -13
-KPX seven seven 9
-KPX seven period -87
-KPX seven one -14
-KPX seven four -62
-KPX seven five -21
-KPX seven eight -3
-KPX seven comma -88
-KPX seven colon -63
-KPX eight seven -6
-KPX eight one -23
-KPX eight four 10
-KPX nine seven -17
-KPX nine one -21
-KPX nine four 4
-KPX A y -35
-KPX A w -23
-KPX A v -37
-KPX A u -12
-KPX A t -18
-KPX A quoteright -61
-KPX A quotedblright -65
-KPX A q -12
-KPX A period 19
-KPX A o -16
-KPX A hyphen 7
-KPX A guilsinglleft -40
-KPX A guillemotleft -43
-KPX A g -14
-KPX A e -9
-KPX A d -13
-KPX A comma 19
-KPX A ccedilla -14
-KPX A c -14
-KPX A b -1
-KPX A a -1
-KPX A Y -90
-KPX A W -51
-KPX A V -66
-KPX A Ugrave -32
-KPX A Udieresis -32
-KPX A Ucircumflex -32
-KPX A Uacute -32
-KPX A U -32
-KPX A T -81
-KPX A Q -35
-KPX A Odieresis -34
-KPX A O -34
-KPX A G -35
-KPX A Ccedilla -33
-KPX A C -33
-KPX B Y -51
-KPX B W -27
-KPX B V -39
-KPX B Oslash -5
-KPX B Ograve -11
-KPX B Odieresis -11
-KPX B Ocircumflex -11
-KPX B Oacute -11
-KPX B OE -2
-KPX B O -11
-KPX B Atilde -32
-KPX B Aring -32
-KPX B Adieresis -32
-KPX B Acircumflex -32
-KPX B Aacute -32
-KPX B AE -20
-KPX B A -32
-KPX C Odieresis -6
-KPX C Oacute -6
-KPX C O -6
-KPX C K 2
-KPX C H 5
-KPX C Aring -29
-KPX C Adieresis -29
-KPX C Aacute -29
-KPX C AE -17
-KPX C A -29
-KPX D Y -56
-KPX D X -35
-KPX D W -20
-KPX D V -35
-KPX D T -17
-KPX D J 2
-KPX D Atilde -37
-KPX D Aring -37
-KPX D Agrave -37
-KPX D Adieresis -37
-KPX D Acircumflex -37
-KPX D Aacute -37
-KPX D A -37
-KPX F u -24
-KPX F r -27
-KPX F period -75
-KPX F oslash -15
-KPX F oe -8
-KPX F odieresis -14
-KPX F oacute -14
-KPX F o -14
-KPX F j -9
-KPX F i -7
-KPX F hyphen 11
-KPX F eacute -7
-KPX F e -7
-KPX F comma -76
-KPX F aring -15
-KPX F ae -17
-KPX F adieresis -15
-KPX F aacute -15
-KPX F a -15
-KPX F Odieresis -16
-KPX F O -16
-KPX F J -25
-KPX F Atilde -63
-KPX F Aring -63
-KPX F Agrave -63
-KPX F Adieresis -63
-KPX F Acircumflex -63
-KPX F Aacute -63
-KPX F A -63
-KPX G Y -56
-KPX G W -20
-KPX G V -36
-KPX G T -17
-KPX G Atilde -8
-KPX G Aring -8
-KPX G Agrave -8
-KPX G Adieresis -8
-KPX G Acircumflex -8
-KPX G Aacute -8
-KPX G AE 4
-KPX G A -8
-KPX J Aring -32
-KPX J Adieresis -32
-KPX J AE -20
-KPX J A -32
-KPX K y -65
-KPX K udieresis -23
-KPX K u -23
-KPX K odieresis -33
-KPX K oacute -33
-KPX K o -33
-KPX K hyphen -44
-KPX K e -25
-KPX K aring -3
-KPX K adieresis -3
-KPX K a -3
-KPX K T 13
-KPX K S -30
-KPX K Odieresis -54
-KPX K Oacute -54
-KPX K OE -44
-KPX K O -54
-KPX K G -55
-KPX K C -53
-KPX L y -55
-KPX L udieresis -7
-KPX L u -7
-KPX L quoteright -138
-KPX L quotedblright -141
-KPX L hyphen -12
-KPX L Y -112
-KPX L W -68
-KPX L V -90
-KPX L Udieresis -24
-KPX L U -24
-KPX L T -95
-KPX L S -2
-KPX L Otilde -29
-KPX L Ograve -29
-KPX L Odieresis -29
-KPX L Ocircumflex -29
-KPX L Oacute -29
-KPX L O -29
-KPX L G -30
-KPX L Ccedilla -26
-KPX L C -26
-KPX L Aring 9
-KPX L Adieresis 9
-KPX L Aacute 9
-KPX L AE 21
-KPX L A 9
-KPX N udieresis 12
-KPX N u 12
-KPX N period 16
-KPX N oslash 11
-KPX N odieresis 11
-KPX N oacute 11
-KPX N o 11
-KPX N eacute 18
-KPX N e 18
-KPX N comma 15
-KPX N aring 13
-KPX N ae 13
-KPX N adieresis 13
-KPX N aacute 13
-KPX N a 13
-KPX N Odieresis 8
-KPX N Oacute 8
-KPX N O 8
-KPX N G 8
-KPX N Ccedilla 9
-KPX N C 9
-KPX N Aring -5
-KPX N Adieresis -5
-KPX N Aacute -5
-KPX N AE 7
-KPX N A -5
-KPX O Y -59
-KPX O X -36
-KPX O W -21
-KPX O V -36
-KPX O T -20
-KPX O Aring -37
-KPX O Adieresis -37
-KPX O Aacute -37
-KPX O AE -26
-KPX O A -37
-KPX P period -94
-KPX P oslash -17
-KPX P oe -8
-KPX P odieresis -14
-KPX P oacute -14
-KPX P o -14
-KPX P eacute -8
-KPX P e -8
-KPX P comma -94
-KPX P aring -7
-KPX P ae -8
-KPX P adieresis -7
-KPX P aacute -7
-KPX P a -7
-KPX P J -44
-KPX P Aring -65
-KPX P Adieresis -65
-KPX P Aacute -65
-KPX P AE -54
-KPX P A -65
-KPX R y 5
-KPX R oe 1
-KPX R odieresis -4
-KPX R oacute -4
-KPX R o -4
-KPX R hyphen 15
-KPX R eacute 2
-KPX R e 2
-KPX R Y -37
-KPX R W -17
-KPX R V -26
-KPX R Udieresis -4
-KPX R U -4
-KPX R Odieresis -6
-KPX R Oacute -6
-KPX R OE 3
-KPX R O -6
-KPX R G -6
-KPX R Ccedilla -5
-KPX R C -5
-KPX S t 1
-KPX S Y -43
-KPX S W -17
-KPX S V -31
-KPX S T -5
-KPX S Aring -20
-KPX S Adieresis -20
-KPX S Aacute -20
-KPX S AE -8
-KPX S A -20
-KPX T y -80
-KPX T w -77
-KPX T v -82
-KPX T u -72
-KPX T semicolon -98
-KPX T s -74
-KPX T r -71
-KPX T period -67
-KPX T oslash -73
-KPX T o -76
-KPX T j -3
-KPX T i -1
-KPX T hyphen -48
-KPX T guilsinglleft -98
-KPX T guillemotleft -101
-KPX T g -75
-KPX T e -69
-KPX T comma -67
-KPX T colon -97
-KPX T c -74
-KPX T ae -73
-KPX T a -73
-KPX T Y 16
-KPX T W 24
-KPX T V 18
-KPX T S 3
-KPX T Otilde -22
-KPX T Oslash -23
-KPX T Ograve -22
-KPX T Odieresis -22
-KPX T Ocircumflex -22
-KPX T Oacute -22
-KPX T OE -11
-KPX T O -22
-KPX T J -87
-KPX T G -22
-KPX T C -20
-KPX T Atilde -87
-KPX T Aring -87
-KPX T Agrave -87
-KPX T Adieresis -87
-KPX T Acircumflex -87
-KPX T Aacute -87
-KPX T AE -75
-KPX T A -87
-KPX U r 5
-KPX U period -4
-KPX U p 7
-KPX U n 5
-KPX U m 6
-KPX U comma -7
-KPX U Atilde -34
-KPX U Aring -34
-KPX U Adieresis -34
-KPX U Acircumflex -34
-KPX U Aacute -34
-KPX U AE -22
-KPX U A -34
-KPX V y -10
-KPX V u -34
-KPX V semicolon -67
-KPX V r -34
-KPX V period -69
-KPX V oslash -48
-KPX V o -50
-KPX V i -5
-KPX V hyphen -21
-KPX V guilsinglleft -72
-KPX V guillemotleft -74
-KPX V g -49
-KPX V e -43
-KPX V comma -69
-KPX V colon -65
-KPX V ae -48
-KPX V a -47
-KPX V T 21
-KPX V S -21
-KPX V Otilde -37
-KPX V Oslash -31
-KPX V Ograve -37
-KPX V Odieresis -37
-KPX V Ocircumflex -37
-KPX V Oacute -37
-KPX V O -37
-KPX V G -38
-KPX V C -36
-KPX V Atilde -71
-KPX V Aring -71
-KPX V Agrave -71
-KPX V Adieresis -71
-KPX V Acircumflex -71
-KPX V Aacute -71
-KPX V AE -59
-KPX V A -71
-KPX W u -23
-KPX W semicolon -54
-KPX W r -24
-KPX W period -45
-KPX W oslash -29
-KPX W o -31
-KPX W i -1
-KPX W hyphen -3
-KPX W guilsinglleft -53
-KPX W guillemotleft -55
-KPX W g -30
-KPX W e -24
-KPX W comma -45
-KPX W colon -53
-KPX W ae -29
-KPX W a -29
-KPX W T 25
-KPX W S -12
-KPX W Otilde -21
-KPX W Oslash -15
-KPX W Ograve -21
-KPX W Odieresis -21
-KPX W Ocircumflex -21
-KPX W Oacute -21
-KPX W O -21
-KPX W G -22
-KPX W C -20
-KPX W Atilde -54
-KPX W Aring -54
-KPX W Agrave -54
-KPX W Adieresis -54
-KPX W Acircumflex -54
-KPX W Aacute -54
-KPX W AE -43
-KPX W A -54
-KPX X y -40
-KPX X u -25
-KPX X o -32
-KPX X hyphen -27
-KPX X e -25
-KPX X a -5
-KPX X Q -37
-KPX X Odieresis -35
-KPX X O -35
-KPX X C -34
-KPX Y v -27
-KPX Y u -48
-KPX Y semicolon -83
-KPX Y period -78
-KPX Y p -45
-KPX Y oslash -67
-KPX Y o -70
-KPX Y i -3
-KPX Y hyphen -50
-KPX Y guilsinglleft -96
-KPX Y guillemotleft -98
-KPX Y g -68
-KPX Y e -63
-KPX Y comma -78
-KPX Y colon -81
-KPX Y ae -67
-KPX Y a -66
-KPX Y T 22
-KPX Y S -29
-KPX Y Otilde -54
-KPX Y Oslash -47
-KPX Y Ograve -54
-KPX Y Odieresis -54
-KPX Y Ocircumflex -54
-KPX Y Oacute -54
-KPX Y O -54
-KPX Y G -54
-KPX Y C -52
-KPX Y Atilde -86
-KPX Y Aring -86
-KPX Y Agrave -86
-KPX Y Adieresis -86
-KPX Y Acircumflex -86
-KPX Y Aacute -86
-KPX Y AE -74
-KPX Y A -86
-KPX Z y -9
-KPX Z v -11
-KPX quoteleft Y -13
-KPX quoteleft W 11
-KPX quoteleft V 2
-KPX quoteleft T -7
-KPX quoteleft Aring -73
-KPX quoteleft Adieresis -73
-KPX quoteleft Aacute -73
-KPX quoteleft AE -62
-KPX quoteleft A -73
-KPX a y -17
-KPX a w -5
-KPX a v -19
-KPX a quoteright -11
-KPX a j -1
-KPX b y -20
-KPX b w -7
-KPX b v -20
-KPX c k 3
-KPX e y -17
-KPX e x -21
-KPX e w -6
-KPX e v -19
-KPX e t -4
-KPX e quoteright -12
-KPX f t 21
-KPX f s -1
-KPX f quoteright 10
-KPX f oslash -9
-KPX f oe -3
-KPX f odieresis -9
-KPX f oacute -9
-KPX f o -9
-KPX f l -3
-KPX f j -6
-KPX f i -3
-KPX f f 21
-KPX f eacute -3
-KPX f e -3
-KPX f aring 1
-KPX f adieresis 1
-KPX f aacute 1
-KPX f a 1
-KPX g r 1
-KPX g odieresis 1
-KPX g oacute 1
-KPX g eacute 8
-KPX g e 8
-KPX g aring 3
-KPX g ae 3
-KPX g adieresis 3
-KPX g a 3
-KPX h y -21
-KPX h quoteright -14
-KPX i j -2
-KPX i T -4
-KPX k udieresis -1
-KPX k u -1
-KPX k s -10
-KPX k period 6
-KPX k odieresis -22
-KPX k oacute -22
-KPX k o -22
-KPX k hyphen -25
-KPX k g -21
-KPX k eacute -15
-KPX k e -15
-KPX k comma 7
-KPX k aring -2
-KPX k ae 1
-KPX k adieresis -2
-KPX k aacute -2
-KPX k a -2
-KPX l y -2
-KPX l v -5
-KPX m y -18
-KPX m w -6
-KPX m v -19
-KPX m p 6
-KPX n y -19
-KPX n w -7
-KPX n v -20
-KPX n quoteright -12
-KPX n p 5
-KPX n T -80
-KPX o y -22
-KPX o x -25
-KPX o w -10
-KPX o v -23
-KPX o t -8
-KPX o quoteright -17
-KPX o T -84
-KPX p y -20
-KPX p t -5
-KPX q u 4
-KPX q c 4
-KPX r z 9
-KPX r y 23
-KPX r x 17
-KPX r w 26
-KPX r v 21
-KPX r t 22
-KPX r semicolon -27
-KPX r s 3
-KPX r r -2
-KPX r quoteright 14
-KPX r q 1
-KPX r period -57
-KPX r oslash -4
-KPX r ograve -1
-KPX r oe 5
-KPX r odieresis -1
-KPX r ocircumflex -1
-KPX r oacute -1
-KPX r o -1
-KPX r n -2
-KPX r m -1
-KPX r l -4
-KPX r j -6
-KPX r i -4
-KPX r hyphen -35
-KPX r h -4
-KPX r g -2
-KPX r f 22
-KPX r egrave 4
-KPX r ecircumflex 4
-KPX r eacute 4
-KPX r e 4
-KPX r comma -57
-KPX r colon -27
-KPX r aring 6
-KPX r agrave 6
-KPX r ae 4
-KPX r adieresis 6
-KPX r acircumflex 6
-KPX r aacute 6
-KPX r a 6
-KPX s t -1
-KPX s quoteright -12
-KPX t semicolon -25
-KPX t quoteright 4
-KPX t odieresis -10
-KPX t oacute -10
-KPX t o -10
-KPX t h 2
-KPX t eacute -3
-KPX t e -3
-KPX t colon -25
-KPX t aring 6
-KPX t ae 7
-KPX t adieresis 6
-KPX t aacute 6
-KPX t a 6
-KPX u quoteright -2
-KPX v semicolon -34
-KPX v s -17
-KPX v period -50
-KPX v oslash -20
-KPX v ograve -22
-KPX v odieresis -22
-KPX v oacute -22
-KPX v o -22
-KPX v l -5
-KPX v g -21
-KPX v egrave -15
-KPX v ecircumflex -15
-KPX v eacute -15
-KPX v e -15
-KPX v comma -51
-KPX v colon -32
-KPX v c -20
-KPX v atilde -15
-KPX v aring -15
-KPX v agrave -15
-KPX v ae -16
-KPX v adieresis -15
-KPX v acircumflex -15
-KPX v aacute -15
-KPX v a -15
-KPX w semicolon -29
-KPX w s -9
-KPX w period -32
-KPX w oslash -8
-KPX w ograve -10
-KPX w odieresis -10
-KPX w oacute -10
-KPX w o -10
-KPX w l -1
-KPX w hyphen 11
-KPX w g -9
-KPX w egrave -3
-KPX w ecircumflex -3
-KPX w eacute -3
-KPX w e -3
-KPX w comma -33
-KPX w colon -27
-KPX w c -8
-KPX w atilde -7
-KPX w aring -7
-KPX w agrave -7
-KPX w ae -8
-KPX w adieresis -7
-KPX w acircumflex -7
-KPX w aacute -7
-KPX w a -7
-KPX x q -20
-KPX x o -24
-KPX x eacute -17
-KPX x e -17
-KPX x c -22
-KPX x a -9
-KPX y semicolon -33
-KPX y s -16
-KPX y period -50
-KPX y oslash -20
-KPX y ograve -22
-KPX y odieresis -22
-KPX y oacute -22
-KPX y o -22
-KPX y l -4
-KPX y g -21
-KPX y egrave -16
-KPX y ecircumflex -16
-KPX y eacute -16
-KPX y e -16
-KPX y comma -51
-KPX y colon -31
-KPX y c -21
-KPX y atilde -14
-KPX y aring -14
-KPX y agrave -14
-KPX y ae -15
-KPX y adieresis -14
-KPX y acircumflex -14
-KPX y aacute -14
-KPX y a -14
-KPX quotedblleft Y -9
-KPX quotedblleft W 16
-KPX quotedblleft V 6
-KPX quotedblleft T -2
-KPX quotedblleft Aring -68
-KPX quotedblleft Adieresis -68
-KPX quotedblleft Aacute -68
-KPX quotedblleft AE -57
-KPX quotedblleft A -68
-KPX guilsinglright Y -107
-KPX guilsinglright W -56
-KPX guilsinglright V -74
-KPX guilsinglright T -104
-KPX guilsinglright Aring -46
-KPX guilsinglright Adieresis -46
-KPX guilsinglright Aacute -46
-KPX guilsinglright AE -35
-KPX guilsinglright A -46
-KPX quotedblbase Y -92
-KPX quotedblbase W -51
-KPX quotedblbase V -73
-KPX quotedblbase T -75
-KPX quotedblbase AE 24
-KPX quotedblbase A 12
-KPX quotedblright Y -7
-KPX quotedblright W 17
-KPX quotedblright V 7
-KPX quotedblright T 1
-KPX quotedblright Aring -69
-KPX quotedblright Adieresis -69
-KPX quotedblright Aacute -69
-KPX quotedblright AE -57
-KPX quotedblright A -69
-KPX guillemotright Y -111
-KPX guillemotright W -60
-KPX guillemotright V -78
-KPX guillemotright T -108
-KPX guillemotright Aring -51
-KPX guillemotright Adieresis -51
-KPX guillemotright Aacute -51
-KPX guillemotright AE -39
-KPX guillemotright A -51
-KPX Oslash A -32
-KPX ae y -19
-KPX ae w -7
-KPX ae v -21
-KPX Adieresis y -35
-KPX Adieresis w -23
-KPX Adieresis v -37
-KPX Adieresis u -12
-KPX Adieresis t -18
-KPX Adieresis quoteright -61
-KPX Adieresis quotedblright -65
-KPX Adieresis q -12
-KPX Adieresis period 19
-KPX Adieresis o -16
-KPX Adieresis hyphen 7
-KPX Adieresis guilsinglleft -40
-KPX Adieresis guillemotleft -43
-KPX Adieresis g -14
-KPX Adieresis d -13
-KPX Adieresis comma 19
-KPX Adieresis c -14
-KPX Adieresis b -1
-KPX Adieresis a -1
-KPX Adieresis Y -90
-KPX Adieresis W -51
-KPX Adieresis V -66
-KPX Adieresis U -32
-KPX Adieresis T -81
-KPX Adieresis Q -35
-KPX Adieresis O -34
-KPX Adieresis G -35
-KPX Adieresis C -33
-KPX Aacute y -35
-KPX Aacute w -23
-KPX Aacute v -37
-KPX Aacute u -12
-KPX Aacute t -18
-KPX Aacute quoteright -61
-KPX Aacute q -12
-KPX Aacute period 19
-KPX Aacute o -16
-KPX Aacute hyphen 7
-KPX Aacute guilsinglleft -40
-KPX Aacute guillemotleft -43
-KPX Aacute g -14
-KPX Aacute e -9
-KPX Aacute d -13
-KPX Aacute comma 19
-KPX Aacute c -14
-KPX Aacute b -1
-KPX Aacute a -1
-KPX Aacute Y -90
-KPX Aacute W -51
-KPX Aacute V -66
-KPX Aacute U -32
-KPX Aacute T -81
-KPX Aacute Q -35
-KPX Aacute O -34
-KPX Aacute G -35
-KPX Aacute C -33
-KPX Agrave period 19
-KPX Agrave comma 19
-KPX Agrave Y -90
-KPX Agrave W -51
-KPX Agrave V -66
-KPX Agrave U -32
-KPX Agrave T -81
-KPX Agrave Q -35
-KPX Agrave O -34
-KPX Agrave G -35
-KPX Agrave C -33
-KPX Acircumflex period 19
-KPX Acircumflex comma 19
-KPX Acircumflex Y -90
-KPX Acircumflex W -51
-KPX Acircumflex V -66
-KPX Acircumflex U -32
-KPX Acircumflex T -81
-KPX Acircumflex Q -35
-KPX Acircumflex O -34
-KPX Acircumflex G -35
-KPX Acircumflex C -33
-KPX Atilde period 19
-KPX Atilde comma 19
-KPX Atilde Y -90
-KPX Atilde W -51
-KPX Atilde V -66
-KPX Atilde U -32
-KPX Atilde T -81
-KPX Atilde Q -35
-KPX Atilde O -34
-KPX Atilde G -35
-KPX Atilde C -33
-KPX Aring y -35
-KPX Aring w -23
-KPX Aring v -37
-KPX Aring u -12
-KPX Aring t -18
-KPX Aring quoteright -61
-KPX Aring quotedblright -65
-KPX Aring q -12
-KPX Aring period 19
-KPX Aring o -16
-KPX Aring hyphen 7
-KPX Aring guilsinglleft -40
-KPX Aring guillemotleft -43
-KPX Aring g -14
-KPX Aring e -9
-KPX Aring d -13
-KPX Aring comma 19
-KPX Aring c -14
-KPX Aring b -1
-KPX Aring a -1
-KPX Aring Y -90
-KPX Aring W -51
-KPX Aring V -66
-KPX Aring U -32
-KPX Aring T -81
-KPX Aring Q -35
-KPX Aring O -34
-KPX Aring G -35
-KPX Aring C -33
-KPX Ccedilla A -28
-KPX Odieresis Y -59
-KPX Odieresis X -36
-KPX Odieresis W -21
-KPX Odieresis V -36
-KPX Odieresis T -20
-KPX Odieresis A -37
-KPX Oacute Y -59
-KPX Oacute W -21
-KPX Oacute V -36
-KPX Oacute T -20
-KPX Oacute A -37
-KPX Ograve Y -59
-KPX Ograve V -36
-KPX Ograve T -20
-KPX Ocircumflex Y -59
-KPX Ocircumflex V -36
-KPX Ocircumflex T -20
-KPX Otilde Y -59
-KPX Otilde V -36
-KPX Otilde T -20
-KPX Udieresis r 5
-KPX Udieresis period -4
-KPX Udieresis p 7
-KPX Udieresis n 5
-KPX Udieresis m 6
-KPX Udieresis comma -7
-KPX Udieresis b 6
-KPX Udieresis A -34
-KPX Uacute r 5
-KPX Uacute period -4
-KPX Uacute p 7
-KPX Uacute n 5
-KPX Uacute m 6
-KPX Uacute comma -7
-KPX Uacute A -34
-KPX Ugrave A -34
-KPX Ucircumflex A -34
-KPX adieresis y -17
-KPX adieresis w -5
-KPX adieresis v -19
-KPX aacute y -17
-KPX aacute w -5
-KPX aacute v -19
-KPX agrave y -17
-KPX agrave w -5
-KPX agrave v -19
-KPX aring y -17
-KPX aring w -5
-KPX aring v -19
-KPX eacute y -17
-KPX eacute w -6
-KPX eacute v -19
-KPX ecircumflex y -17
-KPX ecircumflex w -6
-KPX ecircumflex v -19
-KPX odieresis y -22
-KPX odieresis x -25
-KPX odieresis w -10
-KPX odieresis v -23
-KPX odieresis t -8
-KPX oacute y -22
-KPX oacute w -10
-KPX oacute v -23
-KPX ograve y -22
-KPX ograve w -10
-KPX ograve v -23
-KPX ocircumflex t -8
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-sans-l/n019004l.pfb b/src/fonts/nimbus-sans-l/n019004l.pfb
deleted file mode 100644
index 726f91f..0000000
--- a/src/fonts/nimbus-sans-l/n019004l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019004l.pfm b/src/fonts/nimbus-sans-l/n019004l.pfm
deleted file mode 100644
index 548b140..0000000
--- a/src/fonts/nimbus-sans-l/n019004l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019023l.afm b/src/fonts/nimbus-sans-l/n019023l.afm
deleted file mode 100644
index 01afb06..0000000
--- a/src/fonts/nimbus-sans-l/n019023l.afm
+++ /dev/null
@@ -1,1584 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 14:37:05 2007
-FontName NimbusSanL-ReguItal
-FullName Nimbus Sans L Regular Italic
-FamilyName Nimbus Sans L
-Weight Regular
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle -12
-IsFixedPitch false
-UnderlinePosition -151
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -178 -284 1139 979
-CapHeight 729
-XHeight 524
-Ascender 729
-Descender -213
-StartCharMetrics 562
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 278 ; N exclam ; B 124 0 363 729 ;
-C 34 ; WX 355 ; N quotedbl ; B 177 464 455 709 ;
-C 35 ; WX 556 ; N numbersign ; B 54 -20 649 697 ;
-C 36 ; WX 556 ; N dollar ; B 69 -126 613 770 ;
-C 37 ; WX 889 ; N percent ; B 134 -20 895 709 ;
-C 38 ; WX 667 ; N ampersand ; B 83 -23 644 709 ;
-C 39 ; WX 222 ; N quoteright ; B 166 477 309 708 ;
-C 40 ; WX 333 ; N parenleft ; B 113 -213 446 729 ;
-C 41 ; WX 333 ; N parenright ; B -7 -213 325 729 ;
-C 42 ; WX 389 ; N asterisk ; B 169 438 471 729 ;
-C 43 ; WX 584 ; N plus ; B 92 -11 591 473 ;
-C 44 ; WX 278 ; N comma ; B 55 -148 214 103 ;
-C 45 ; WX 333 ; N hyphen ; B 97 240 351 312 ;
-C 46 ; WX 278 ; N period ; B 87 0 213 103 ;
-C 47 ; WX 278 ; N slash ; B -12 -20 434 729 ;
-C 48 ; WX 556 ; N zero ; B 98 -23 598 709 ;
-C 49 ; WX 556 ; N one ; B 208 0 498 709 ;
-C 50 ; WX 556 ; N two ; B 34 0 620 709 ;
-C 51 ; WX 556 ; N three ; B 71 -23 599 709 ;
-C 52 ; WX 556 ; N four ; B 63 0 573 709 ;
-C 53 ; WX 556 ; N five ; B 70 -23 629 709 ;
-C 54 ; WX 556 ; N six ; B 93 -23 611 709 ;
-C 55 ; WX 556 ; N seven ; B 137 0 671 709 ;
-C 56 ; WX 556 ; N eight ; B 74 -23 604 709 ;
-C 57 ; WX 556 ; N nine ; B 83 -23 599 709 ;
-C 58 ; WX 278 ; N colon ; B 110 0 326 524 ;
-C 59 ; WX 278 ; N semicolon ; B 78 -148 325 524 ;
-C 60 ; WX 584 ; N less ; B 87 -9 635 474 ;
-C 61 ; WX 584 ; N equal ; B 74 111 609 355 ;
-C 62 ; WX 584 ; N greater ; B 48 -9 596 474 ;
-C 63 ; WX 556 ; N question ; B 184 0 630 741 ;
-C 64 ; WX 1015 ; N at ; B 80 -142 1036 741 ;
-C 65 ; WX 667 ; N A ; B 17 0 653 729 ;
-C 66 ; WX 667 ; N B ; B 79 0 711 729 ;
-C 67 ; WX 722 ; N C ; B 112 -23 770 741 ;
-C 68 ; WX 722 ; N D ; B 89 0 759 729 ;
-C 69 ; WX 667 ; N E ; B 90 0 751 729 ;
-C 70 ; WX 611 ; N F ; B 90 0 734 729 ;
-C 71 ; WX 778 ; N G ; B 109 -23 809 741 ;
-C 72 ; WX 722 ; N H ; B 83 0 799 729 ;
-C 73 ; WX 278 ; N I ; B 100 0 349 729 ; L J IJ ;
-C 74 ; WX 500 ; N J ; B 47 -23 581 729 ;
-C 75 ; WX 667 ; N K ; B 79 0 813 729 ;
-C 76 ; WX 556 ; N L ; B 80 0 551 729 ; L periodcentered Ldot ;
-C 77 ; WX 833 ; N M ; B 75 0 916 729 ;
-C 78 ; WX 722 ; N N ; B 76 0 801 729 ; L o afii61352 ;
-C 79 ; WX 778 ; N O ; B 104 -23 828 741 ;
-C 80 ; WX 667 ; N P ; B 91 0 733 729 ;
-C 81 ; WX 778 ; N Q ; B 104 -59 828 741 ;
-C 82 ; WX 722 ; N R ; B 93 0 770 729 ;
-C 83 ; WX 667 ; N S ; B 89 -23 714 741 ;
-C 84 ; WX 611 ; N T ; B 158 0 748 729 ; L M trademark ;
-C 85 ; WX 722 ; N U ; B 124 -23 800 729 ;
-C 86 ; WX 667 ; N V ; B 185 0 800 729 ;
-C 87 ; WX 944 ; N W ; B 177 0 1084 729 ;
-C 88 ; WX 667 ; N X ; B 22 0 794 729 ;
-C 89 ; WX 667 ; N Y ; B 168 0 816 729 ;
-C 90 ; WX 611 ; N Z ; B 28 0 737 729 ;
-C 91 ; WX 278 ; N bracketleft ; B 19 -213 405 729 ;
-C 92 ; WX 278 ; N backslash ; B 147 -20 280 729 ;
-C 93 ; WX 278 ; N bracketright ; B -23 -213 364 729 ;
-C 94 ; WX 469 ; N asciicircum ; B 115 329 496 709 ;
-C 95 ; WX 556 ; N underscore ; B -59 -176 551 -126 ;
-C 96 ; WX 222 ; N quoteleft ; B 163 477 308 709 ;
-C 97 ; WX 556 ; N a ; B 65 -23 568 539 ;
-C 98 ; WX 556 ; N b ; B 54 -23 588 729 ;
-C 99 ; WX 500 ; N c ; B 76 -23 554 539 ;
-C 100 ; WX 556 ; N d ; B 73 -23 650 729 ;
-C 101 ; WX 556 ; N e ; B 84 -23 580 539 ;
-C 102 ; WX 278 ; N f ; B 89 0 413 732 ; L l fl ; L i fi ;
-C 103 ; WX 556 ; N g ; B 32 -218 601 539 ;
-C 104 ; WX 556 ; N h ; B 70 0 574 729 ;
-C 105 ; WX 222 ; N i ; B 66 0 305 729 ; L j ij ;
-C 106 ; WX 222 ; N j ; B -65 -218 308 729 ;
-C 107 ; WX 500 ; N k ; B 58 0 584 729 ;
-C 108 ; WX 222 ; N l ; B 68 0 307 729 ; L periodcentered ldot ;
-C 109 ; WX 833 ; N m ; B 71 0 852 539 ;
-C 110 ; WX 556 ; N n ; B 70 0 574 539 ;
-C 111 ; WX 556 ; N o ; B 80 -23 576 539 ;
-C 112 ; WX 556 ; N p ; B 7 -213 586 539 ;
-C 113 ; WX 556 ; N q ; B 71 -213 607 539 ;
-C 114 ; WX 333 ; N r ; B 69 0 436 539 ;
-C 115 ; WX 500 ; N s ; B 61 -23 520 539 ;
-C 116 ; WX 278 ; N t ; B 97 -23 366 668 ;
-C 117 ; WX 556 ; N u ; B 88 -23 594 524 ;
-C 118 ; WX 500 ; N v ; B 122 0 598 524 ;
-C 119 ; WX 722 ; N w ; B 118 0 820 524 ;
-C 120 ; WX 500 ; N x ; B 17 0 583 524 ;
-C 121 ; WX 500 ; N y ; B 8 -218 590 524 ;
-C 122 ; WX 500 ; N z ; B 31 0 557 524 ;
-C 123 ; WX 334 ; N braceleft ; B 91 -213 431 729 ;
-C 124 ; WX 260 ; N bar ; B 54 -212 315 729 ;
-C 125 ; WX 334 ; N braceright ; B -16 -213 324 729 ;
-C 126 ; WX 584 ; N asciitilde ; B 137 268 594 438 ;
-C 161 ; WX 333 ; N exclamdown ; B 76 -205 317 524 ;
-C 162 ; WX 556 ; N cent ; B 96 -120 585 628 ;
-C 163 ; WX 556 ; N sterling ; B 44 -23 628 729 ;
-C 164 ; WX 167 ; N fraction ; B -178 -20 486 709 ;
-C 165 ; WX 556 ; N yen ; B 100 0 696 709 ;
-C 166 ; WX 556 ; N florin ; B -32 -212 696 738 ;
-C 167 ; WX 556 ; N section ; B 63 -213 589 729 ;
-C 168 ; WX 556 ; N currency ; B 110 133 593 556 ;
-C 169 ; WX 191 ; N quotesingle ; B 173 464 292 709 ;
-C 170 ; WX 333 ; N quotedblleft ; B 146 477 449 709 ;
-C 171 ; WX 556 ; N guillemotleft ; B 147 106 548 438 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 140 106 336 438 ;
-C 173 ; WX 333 ; N guilsinglright ; B 109 106 307 438 ;
-C 174 ; WX 500 ; N fi ; B 83 0 591 732 ;
-C 175 ; WX 500 ; N fl ; B 88 0 585 732 ;
-C 177 ; WX 556 ; N endash ; B 46 240 628 312 ;
-C 178 ; WX 556 ; N dagger ; B 127 -177 620 709 ;
-C 179 ; WX 556 ; N daggerdbl ; B 51 -177 620 709 ;
-C 180 ; WX 278 ; N periodcentered ; B 166 192 293 295 ;
-C 182 ; WX 537 ; N paragraph ; B 145 -178 677 729 ;
-C 183 ; WX 350 ; N bullet ; B 120 220 376 470 ;
-C 184 ; WX 222 ; N quotesinglbase ; B 37 -128 180 103 ;
-C 185 ; WX 333 ; N quotedblbase ; B 20 -128 322 103 ;
-C 186 ; WX 333 ; N quotedblright ; B 150 477 452 708 ;
-C 187 ; WX 556 ; N guillemotright ; B 121 106 518 438 ;
-C 188 ; WX 1000 ; N ellipsis ; B 115 0 907 103 ;
-C 189 ; WX 1000 ; N perthousand ; B 93 -20 1024 738 ;
-C 191 ; WX 611 ; N questiondown ; B 86 -217 531 524 ;
-C 193 ; WX 333 ; N grave ; B 179 592 357 740 ;
-C 194 ; WX 333 ; N acute ; B 218 592 458 740 ;
-C 195 ; WX 333 ; N circumflex ; B 146 591 433 741 ;
-C 196 ; WX 333 ; N tilde ; B 130 611 471 719 ;
-C 197 ; WX 333 ; N macron ; B 160 627 450 696 ;
-C 198 ; WX 333 ; N breve ; B 165 594 471 729 ;
-C 199 ; WX 333 ; N dotaccent ; B 244 612 370 715 ;
-C 200 ; WX 333 ; N dieresis ; B 159 612 446 715 ;
-C 202 ; WX 333 ; N ring ; B 216 579 396 754 ;
-C 203 ; WX 333 ; N cedilla ; B 1 -214 264 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 91 590 505 740 ;
-C 206 ; WX 333 ; N ogonek ; B 35 -205 246 0 ;
-C 207 ; WX 333 ; N caron ; B 176 592 463 740 ;
-C 208 ; WX 1000 ; N emdash ; B 42 240 1068 312 ;
-C 225 ; WX 1000 ; N AE ; B 11 0 1087 729 ;
-C 227 ; WX 370 ; N ordfeminine ; B 107 303 441 742 ;
-C 232 ; WX 556 ; N Lslash ; B 75 0 570 729 ;
-C 233 ; WX 778 ; N Oslash ; B 32 -24 867 741 ;
-C 234 ; WX 1000 ; N OE ; B 101 -23 1108 741 ;
-C 235 ; WX 365 ; N ordmasculine ; B 114 303 452 742 ;
-C 241 ; WX 889 ; N ae ; B 59 -23 915 539 ;
-C 245 ; WX 278 ; N dotlessi ; B 94 0 290 527 ;
-C 248 ; WX 222 ; N lslash ; B 62 0 312 729 ;
-C 249 ; WX 611 ; N oslash ; B 19 -30 639 541 ;
-C 250 ; WX 944 ; N oe ; B 85 -23 966 539 ;
-C 251 ; WX 611 ; N germandbls ; B 126 -23 655 729 ;
-C -1 ; WX 667 ; N Adieresis ; B 17 0 662 914 ;
-C -1 ; WX 667 ; N Aacute ; B 17 0 667 939 ;
-C -1 ; WX 667 ; N Agrave ; B 17 0 653 939 ;
-C -1 ; WX 667 ; N Acircumflex ; B 17 0 653 940 ;
-C -1 ; WX 667 ; N Abreve ; B 17 0 683 928 ;
-C -1 ; WX 667 ; N Atilde ; B 17 0 680 918 ;
-C -1 ; WX 667 ; N Aring ; B 17 0 653 953 ;
-C -1 ; WX 667 ; N Aogonek ; B 17 -205 663 729 ;
-C -1 ; WX 722 ; N Ccedilla ; B 112 -214 770 741 ;
-C -1 ; WX 722 ; N Cacute ; B 112 -23 770 939 ;
-C -1 ; WX 722 ; N Ccaron ; B 112 -23 770 939 ;
-C -1 ; WX 722 ; N Dcaron ; B 89 0 759 939 ;
-C -1 ; WX 667 ; N Edieresis ; B 90 0 751 914 ;
-C -1 ; WX 667 ; N Eacute ; B 90 0 751 939 ;
-C -1 ; WX 667 ; N Egrave ; B 90 0 751 939 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 90 0 751 940 ;
-C -1 ; WX 667 ; N Ecaron ; B 90 0 751 939 ;
-C -1 ; WX 667 ; N Edotaccent ; B 90 0 751 914 ;
-C -1 ; WX 667 ; N Eogonek ; B 90 -205 751 729 ;
-C -1 ; WX 778 ; N Gbreve ; B 109 -23 809 928 ;
-C -1 ; WX 278 ; N Idieresis ; B 100 0 467 907 ;
-C -1 ; WX 278 ; N Iacute ; B 100 0 479 939 ;
-C -1 ; WX 278 ; N Igrave ; B 100 0 378 939 ;
-C -1 ; WX 278 ; N Icircumflex ; B 100 0 454 940 ;
-C -1 ; WX 278 ; N Idotaccent ; B 100 0 389 914 ;
-C -1 ; WX 556 ; N Lacute ; B 80 0 551 939 ;
-C -1 ; WX 556 ; N Lcaron ; B 80 0 551 729 ;
-C -1 ; WX 722 ; N Nacute ; B 76 0 801 939 ;
-C -1 ; WX 722 ; N Ncaron ; B 76 0 801 939 ;
-C -1 ; WX 722 ; N Ntilde ; B 76 0 801 918 ;
-C -1 ; WX 778 ; N Odieresis ; B 104 -23 828 914 ;
-C -1 ; WX 778 ; N Oacute ; B 104 -23 828 939 ;
-C -1 ; WX 778 ; N Ograve ; B 104 -23 828 939 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 104 -23 828 940 ;
-C -1 ; WX 778 ; N Otilde ; B 104 -23 828 918 ;
-C -1 ; WX 778 ; N Ohungarumlaut ; B 104 -23 841 939 ;
-C -1 ; WX 722 ; N Racute ; B 93 0 770 939 ;
-C -1 ; WX 722 ; N Rcaron ; B 93 0 770 939 ;
-C -1 ; WX 667 ; N Sacute ; B 89 -23 714 939 ;
-C -1 ; WX 667 ; N Scaron ; B 89 -23 714 939 ;
-C -1 ; WX 667 ; N Scedilla ; B 89 -214 714 741 ;
-C -1 ; WX 611 ; N Tcaron ; B 158 0 748 939 ;
-C -1 ; WX 722 ; N Udieresis ; B 124 -23 800 914 ;
-C -1 ; WX 722 ; N Uacute ; B 124 -23 800 939 ;
-C -1 ; WX 722 ; N Ugrave ; B 124 -23 800 939 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 124 -23 800 940 ;
-C -1 ; WX 722 ; N Uring ; B 124 -23 800 953 ;
-C -1 ; WX 722 ; N Uhungarumlaut ; B 124 -23 806 939 ;
-C -1 ; WX 667 ; N Yacute ; B 168 0 816 939 ;
-C -1 ; WX 611 ; N Zacute ; B 28 0 737 939 ;
-C -1 ; WX 611 ; N Zcaron ; B 28 0 737 939 ;
-C -1 ; WX 611 ; N Zdotaccent ; B 28 0 737 914 ;
-C -1 ; WX 667 ; N Amacron ; B 17 0 663 895 ;
-C -1 ; WX 611 ; N Tcommaaccent ; B 158 -284 748 729 ;
-C -1 ; WX 667 ; N Ydieresis ; B 168 0 816 914 ;
-C -1 ; WX 667 ; N Emacron ; B 90 0 751 895 ;
-C -1 ; WX 278 ; N Imacron ; B 100 0 458 895 ;
-C -1 ; WX 278 ; N Iogonek ; B 28 -205 349 729 ;
-C -1 ; WX 667 ; N Kcommaaccent ; B 79 -284 813 729 ;
-C -1 ; WX 556 ; N Lcommaaccent ; B 80 -284 551 729 ;
-C -1 ; WX 722 ; N Ncommaaccent ; B 76 -284 801 729 ;
-C -1 ; WX 778 ; N Omacron ; B 104 -23 828 895 ;
-C -1 ; WX 722 ; N Rcommaaccent ; B 93 -284 770 729 ;
-C -1 ; WX 778 ; N Gcommaaccent ; B 109 -284 809 741 ;
-C -1 ; WX 722 ; N Umacron ; B 124 -23 800 895 ;
-C -1 ; WX 722 ; N Uogonek ; B 124 -205 800 729 ;
-C -1 ; WX 556 ; N adieresis ; B 65 -23 568 715 ;
-C -1 ; WX 556 ; N aacute ; B 65 -23 570 740 ;
-C -1 ; WX 556 ; N agrave ; B 65 -23 568 740 ;
-C -1 ; WX 556 ; N acircumflex ; B 65 -23 568 741 ;
-C -1 ; WX 556 ; N abreve ; B 65 -23 582 729 ;
-C -1 ; WX 556 ; N atilde ; B 65 -23 583 719 ;
-C -1 ; WX 556 ; N aring ; B 65 -23 568 754 ;
-C -1 ; WX 556 ; N aogonek ; B 65 -205 571 539 ;
-C -1 ; WX 500 ; N cacute ; B 76 -23 575 740 ;
-C -1 ; WX 500 ; N ccaron ; B 76 -23 563 740 ;
-C -1 ; WX 500 ; N ccedilla ; B 76 -214 554 539 ;
-C -1 ; WX 650 ; N dcaron ; B 73 -23 810 729 ;
-C -1 ; WX 556 ; N edieresis ; B 84 -23 580 715 ;
-C -1 ; WX 556 ; N eacute ; B 84 -23 580 740 ;
-C -1 ; WX 556 ; N egrave ; B 84 -23 580 740 ;
-C -1 ; WX 556 ; N ecircumflex ; B 84 -23 580 741 ;
-C -1 ; WX 556 ; N ecaron ; B 84 -23 580 740 ;
-C -1 ; WX 556 ; N edotaccent ; B 84 -23 580 715 ;
-C -1 ; WX 556 ; N eogonek ; B 84 -205 580 539 ;
-C -1 ; WX 556 ; N gbreve ; B 32 -218 601 729 ;
-C -1 ; WX 278 ; N idieresis ; B 94 0 419 708 ;
-C -1 ; WX 278 ; N iacute ; B 94 0 431 740 ;
-C -1 ; WX 278 ; N igrave ; B 94 0 330 740 ;
-C -1 ; WX 278 ; N icircumflex ; B 94 0 406 741 ;
-C -1 ; WX 222 ; N lacute ; B 68 0 463 939 ;
-C -1 ; WX 307 ; N lcaron ; B 68 0 467 729 ;
-C -1 ; WX 556 ; N nacute ; B 70 0 580 740 ;
-C -1 ; WX 556 ; N ncaron ; B 70 0 578 740 ;
-C -1 ; WX 556 ; N ntilde ; B 70 0 589 719 ;
-C -1 ; WX 556 ; N odieresis ; B 80 -23 576 715 ;
-C -1 ; WX 556 ; N oacute ; B 80 -23 576 740 ;
-C -1 ; WX 556 ; N ograve ; B 80 -23 576 740 ;
-C -1 ; WX 556 ; N ocircumflex ; B 80 -23 576 741 ;
-C -1 ; WX 556 ; N otilde ; B 80 -23 583 719 ;
-C -1 ; WX 556 ; N ohungarumlaut ; B 80 -23 683 740 ;
-C -1 ; WX 333 ; N racute ; B 69 0 498 740 ;
-C -1 ; WX 500 ; N sacute ; B 61 -23 545 740 ;
-C -1 ; WX 500 ; N scaron ; B 61 -23 547 740 ;
-C -1 ; WX 500 ; N scommaaccent ; B 61 -284 520 539 ;
-C -1 ; WX 319 ; N tcaron ; B 97 -23 492 801 ;
-C -1 ; WX 556 ; N udieresis ; B 88 -23 594 715 ;
-C -1 ; WX 556 ; N uacute ; B 88 -23 594 740 ;
-C -1 ; WX 556 ; N ugrave ; B 88 -23 594 740 ;
-C -1 ; WX 556 ; N ucircumflex ; B 88 -23 594 741 ;
-C -1 ; WX 556 ; N uring ; B 88 -23 594 754 ;
-C -1 ; WX 556 ; N uhungarumlaut ; B 88 -23 683 740 ;
-C -1 ; WX 500 ; N yacute ; B 8 -218 590 740 ;
-C -1 ; WX 500 ; N zacute ; B 31 0 557 740 ;
-C -1 ; WX 500 ; N zcaron ; B 31 0 557 740 ;
-C -1 ; WX 500 ; N zdotaccent ; B 31 0 557 715 ;
-C -1 ; WX 500 ; N ydieresis ; B 8 -218 590 715 ;
-C -1 ; WX 278 ; N tcommaaccent ; B 55 -284 366 668 ;
-C -1 ; WX 556 ; N amacron ; B 65 -23 568 696 ;
-C -1 ; WX 556 ; N emacron ; B 84 -23 580 696 ;
-C -1 ; WX 222 ; N imacron ; B 66 0 373 696 ;
-C -1 ; WX 500 ; N kcommaaccent ; B 58 -284 584 729 ;
-C -1 ; WX 222 ; N lcommaaccent ; B -1 -284 307 729 ;
-C -1 ; WX 556 ; N ncommaaccent ; B 70 -284 574 539 ;
-C -1 ; WX 556 ; N omacron ; B 80 -23 576 696 ;
-C -1 ; WX 333 ; N rcommaaccent ; B 5 -284 436 539 ;
-C -1 ; WX 556 ; N umacron ; B 88 -23 594 696 ;
-C -1 ; WX 556 ; N uogonek ; B 88 -205 594 524 ;
-C -1 ; WX 333 ; N rcaron ; B 69 0 486 740 ;
-C -1 ; WX 500 ; N scedilla ; B 61 -214 521 539 ;
-C -1 ; WX 527 ; N gcommaaccent ; B 3 -218 572 813 ;
-C -1 ; WX 222 ; N iogonek ; B 0 -205 305 729 ;
-C -1 ; WX 667 ; N Scommaaccent ; B 89 -284 714 741 ;
-C -1 ; WX 722 ; N Eth ; B 89 0 759 729 ;
-C -1 ; WX 722 ; N Dcroat ; B 89 0 759 729 ;
-C -1 ; WX 667 ; N Thorn ; B 91 0 708 729 ;
-C -1 ; WX 556 ; N dcroat ; B 73 -23 695 729 ;
-C -1 ; WX 556 ; N eth ; B 80 -23 576 743 ;
-C -1 ; WX 556 ; N thorn ; B 7 -213 586 729 ;
-C -1 ; WX 556 ; N Euro ; B 12 -22 636 709 ;
-C -1 ; WX 390 ; N onesuperior ; B 205 284 393 709 ;
-C -1 ; WX 390 ; N twosuperior ; B 100 284 468 709 ;
-C -1 ; WX 390 ; N threesuperior ; B 123 270 455 709 ;
-C -1 ; WX 606 ; N degree ; B 291 383 594 686 ;
-C -1 ; WX 584 ; N minus ; B 81 197 601 269 ;
-C -1 ; WX 584 ; N multiply ; B 113 34 568 427 ;
-C -1 ; WX 584 ; N divide ; B 92 0 591 462 ;
-C -1 ; WX 1000 ; N trademark ; B 208 292 1096 729 ;
-C -1 ; WX 584 ; N plusminus ; B 50 0 625 633 ;
-C -1 ; WX 947 ; N onehalf ; B 202 -20 965 709 ;
-C -1 ; WX 947 ; N onequarter ; B 205 -20 938 709 ;
-C -1 ; WX 947 ; N threequarters ; B 123 -20 938 709 ;
-C -1 ; WX 333 ; N commaaccent ; B 57 -284 205 -60 ;
-C -1 ; WX 737 ; N copyright ; B 55 -22 836 742 ;
-C -1 ; WX 737 ; N registered ; B 55 -22 836 742 ;
-C -1 ; WX 489 ; N lozenge ; B 16 0 462 744 ;
-C -1 ; WX 712 ; N Delta ; B 10 0 701 729 ;
-C -1 ; WX 584 ; N notequal ; B 74 2 609 480 ;
-C -1 ; WX 542 ; N radical ; B 102 -36 705 913 ;
-C -1 ; WX 584 ; N lessequal ; B 45 0 659 584 ;
-C -1 ; WX 584 ; N greaterequal ; B 56 0 626 584 ;
-C -1 ; WX 584 ; N logicalnot ; B 99 86 619 377 ;
-C -1 ; WX 711 ; N summation ; B -18 -97 760 762 ;
-C -1 ; WX 490 ; N partialdiff ; B 22 -15 458 750 ;
-C -1 ; WX 260 ; N brokenbar ; B 54 -212 315 729 ;
-C -1 ; WX 556 ; N mu ; B 18 -220 593 524 ;
-C -1 ; WX 667 ; N afii10017 ; B 17 0 653 729 ;
-C -1 ; WX 639 ; N afii10018 ; B 79 0 723 729 ;
-C -1 ; WX 667 ; N afii10019 ; B 79 0 711 729 ;
-C -1 ; WX 611 ; N afii10020 ; B 90 0 734 729 ;
-C -1 ; WX 816 ; N afii10021 ; B 31 -135 868 729 ;
-C -1 ; WX 667 ; N afii10022 ; B 90 0 751 729 ;
-C -1 ; WX 667 ; N afii10023 ; B 90 0 751 914 ;
-C -1 ; WX 897 ; N afii10024 ; B 22 0 1024 729 ;
-C -1 ; WX 652 ; N afii10025 ; B 71 -23 695 741 ;
-C -1 ; WX 731 ; N afii10026 ; B 83 0 808 729 ;
-C -1 ; WX 731 ; N afii10027 ; B 83 0 808 928 ;
-C -1 ; WX 664 ; N afii10028 ; B 79 0 810 729 ;
-C -1 ; WX 646 ; N afii10029 ; B 6 0 721 729 ;
-C -1 ; WX 833 ; N afii10030 ; B 75 0 916 729 ;
-C -1 ; WX 722 ; N afii10031 ; B 83 0 799 729 ;
-C -1 ; WX 778 ; N afii10032 ; B 104 -23 828 741 ;
-C -1 ; WX 722 ; N afii10033 ; B 83 0 799 729 ;
-C -1 ; WX 667 ; N afii10034 ; B 91 0 733 729 ;
-C -1 ; WX 722 ; N afii10035 ; B 112 -23 770 741 ;
-C -1 ; WX 611 ; N afii10036 ; B 158 0 748 729 ;
-C -1 ; WX 530 ; N afii10037 ; B 22 0 657 729 ;
-C -1 ; WX 891 ; N afii10038 ; B 99 0 914 729 ;
-C -1 ; WX 667 ; N afii10039 ; B 22 0 794 729 ;
-C -1 ; WX 722 ; N afii10040 ; B 83 -135 799 729 ;
-C -1 ; WX 642 ; N afii10041 ; B 159 0 691 729 ;
-C -1 ; WX 836 ; N afii10042 ; B 60 0 885 729 ;
-C -1 ; WX 837 ; N afii10043 ; B 60 -135 885 729 ;
-C -1 ; WX 866 ; N afii10044 ; B 158 0 841 729 ;
-C -1 ; WX 886 ; N afii10045 ; B 83 0 963 729 ;
-C -1 ; WX 698 ; N afii10046 ; B 83 0 673 729 ;
-C -1 ; WX 717 ; N afii10047 ; B 104 -23 767 741 ;
-C -1 ; WX 1049 ; N afii10048 ; B 60 -23 1099 741 ;
-C -1 ; WX 691 ; N afii10049 ; B 22 0 768 729 ;
-C -1 ; WX 556 ; N afii10065 ; B 65 -23 568 539 ;
-C -1 ; WX 556 ; N afii10066 ; B 72 -23 626 776 ;
-C -1 ; WX 538 ; N afii10067 ; B 70 0 548 525 ;
-C -1 ; WX 430 ; N afii10068 ; B 70 0 476 524 ;
-C -1 ; WX 640 ; N afii10069 ; B -18 -120 596 524 ;
-C -1 ; WX 556 ; N afii10070 ; B 84 -23 580 539 ;
-C -1 ; WX 556 ; N afii10071 ; B 84 -23 580 715 ;
-C -1 ; WX 818 ; N afii10072 ; B 17 0 901 524 ;
-C -1 ; WX 495 ; N afii10073 ; B 60 -23 520 539 ;
-C -1 ; WX 560 ; N afii10074 ; B 70 0 598 524 ;
-C -1 ; WX 560 ; N afii10075 ; B 70 0 598 729 ;
-C -1 ; WX 510 ; N afii10076 ; B 70 0 593 524 ;
-C -1 ; WX 556 ; N afii10077 ; B 14 0 543 524 ;
-C -1 ; WX 621 ; N afii10078 ; B 70 0 659 524 ;
-C -1 ; WX 561 ; N afii10079 ; B 70 0 599 524 ;
-C -1 ; WX 556 ; N afii10080 ; B 80 -23 576 539 ;
-C -1 ; WX 560 ; N afii10081 ; B 70 0 598 524 ;
-C -1 ; WX 556 ; N afii10082 ; B 7 -213 586 539 ;
-C -1 ; WX 500 ; N afii10083 ; B 76 -23 554 539 ;
-C -1 ; WX 400 ; N afii10084 ; B 100 0 488 524 ;
-C -1 ; WX 500 ; N afii10085 ; B 8 -218 590 524 ;
-C -1 ; WX 916 ; N afii10086 ; B 71 -218 946 674 ;
-C -1 ; WX 500 ; N afii10087 ; B 17 0 583 524 ;
-C -1 ; WX 560 ; N afii10088 ; B 70 -120 598 524 ;
-C -1 ; WX 497 ; N afii10089 ; B 133 0 535 524 ;
-C -1 ; WX 695 ; N afii10090 ; B 70 0 733 524 ;
-C -1 ; WX 695 ; N afii10091 ; B 70 -120 733 524 ;
-C -1 ; WX 640 ; N afii10092 ; B 99 0 640 525 ;
-C -1 ; WX 734 ; N afii10093 ; B 70 0 772 525 ;
-C -1 ; WX 523 ; N afii10094 ; B 70 0 523 525 ;
-C -1 ; WX 534 ; N afii10095 ; B 80 -23 554 539 ;
-C -1 ; WX 768 ; N afii10096 ; B 70 -23 806 539 ;
-C -1 ; WX 564 ; N afii10097 ; B 16 0 602 525 ;
-C -1 ; WX 667 ; N uni0400 ; B 90 0 751 949 ;
-C -1 ; WX 686 ; N afii10051 ; B 81 -140 696 729 ;
-C -1 ; WX 611 ; N afii10052 ; B 90 0 734 949 ;
-C -1 ; WX 717 ; N afii10053 ; B 104 -23 767 741 ;
-C -1 ; WX 667 ; N afii10054 ; B 13 -23 636 741 ;
-C -1 ; WX 278 ; N afii10055 ; B 100 0 349 729 ;
-C -1 ; WX 278 ; N afii10056 ; B 100 0 467 907 ;
-C -1 ; WX 500 ; N afii10057 ; B 47 -23 581 729 ;
-C -1 ; WX 1087 ; N afii10058 ; B 6 0 1062 729 ;
-C -1 ; WX 1164 ; N afii10059 ; B 83 0 1139 729 ;
-C -1 ; WX 646 ; N afii10060 ; B 81 0 656 729 ;
-C -1 ; WX 664 ; N afii10061 ; B 79 0 810 949 ;
-C -1 ; WX 731 ; N uni040D ; B 83 0 808 949 ;
-C -1 ; WX 530 ; N afii10062 ; B 22 0 657 936 ;
-C -1 ; WX 722 ; N afii10145 ; B 83 -135 799 729 ;
-C -1 ; WX 556 ; N uni0450 ; B 84 -23 580 747 ;
-C -1 ; WX 556 ; N afii10099 ; B 70 -126 570 729 ;
-C -1 ; WX 430 ; N afii10100 ; B 70 0 555 747 ;
-C -1 ; WX 534 ; N afii10101 ; B 80 -23 554 539 ;
-C -1 ; WX 500 ; N afii10102 ; B 7 -23 469 539 ;
-C -1 ; WX 222 ; N afii10103 ; B 66 0 305 729 ;
-C -1 ; WX 278 ; N afii10104 ; B 94 0 419 708 ;
-C -1 ; WX 222 ; N afii10105 ; B -65 -218 308 729 ;
-C -1 ; WX 786 ; N afii10106 ; B 14 0 800 525 ;
-C -1 ; WX 796 ; N afii10107 ; B 14 0 801 525 ;
-C -1 ; WX 556 ; N afii10108 ; B 70 0 574 729 ;
-C -1 ; WX 510 ; N afii10109 ; B 70 0 613 747 ;
-C -1 ; WX 560 ; N uni045D ; B 70 0 598 747 ;
-C -1 ; WX 500 ; N afii10110 ; B 8 -218 590 734 ;
-C -1 ; WX 560 ; N afii10193 ; B 70 -120 598 524 ;
-C -1 ; WX 698 ; N uni048C ; B 83 0 674 729 ;
-C -1 ; WX 523 ; N uni048D ; B 56 0 524 525 ;
-C -1 ; WX 667 ; N uni048E ; B 91 0 734 729 ;
-C -1 ; WX 556 ; N uni048F ; B 7 -218 587 539 ;
-C -1 ; WX 611 ; N afii10050 ; B 2 0 667 825 ;
-C -1 ; WX 430 ; N afii10098 ; B 3 0 432 629 ;
-C -1 ; WX 611 ; N uni0492 ; B 90 0 734 729 ;
-C -1 ; WX 430 ; N uni0493 ; B 44 0 476 524 ;
-C -1 ; WX 611 ; N uni0494 ; B 90 -140 734 729 ;
-C -1 ; WX 430 ; N uni0495 ; B 70 -126 476 524 ;
-C -1 ; WX 897 ; N uni0496 ; B 22 -135 1024 729 ;
-C -1 ; WX 818 ; N uni0497 ; B 17 -120 901 524 ;
-C -1 ; WX 652 ; N uni0498 ; B 71 -205 695 741 ;
-C -1 ; WX 495 ; N uni0499 ; B 60 -205 520 539 ;
-C -1 ; WX 664 ; N uni049A ; B 79 -135 810 729 ;
-C -1 ; WX 510 ; N uni049B ; B 70 -120 593 524 ;
-C -1 ; WX 664 ; N uni049C ; B 79 0 810 729 ;
-C -1 ; WX 510 ; N uni049D ; B 70 0 593 524 ;
-C -1 ; WX 664 ; N uni049E ; B 79 0 810 729 ;
-C -1 ; WX 510 ; N uni049F ; B 70 0 593 524 ;
-C -1 ; WX 704 ; N uni04A0 ; B 25 0 850 729 ;
-C -1 ; WX 618 ; N uni04A1 ; B 90 0 701 525 ;
-C -1 ; WX 722 ; N uni04A2 ; B 83 -135 799 729 ;
-C -1 ; WX 561 ; N uni04A3 ; B 70 -120 599 524 ;
-C -1 ; WX 1010 ; N uni04A4 ; B 83 0 1133 729 ;
-C -1 ; WX 753 ; N uni04A5 ; B 70 0 799 524 ;
-C -1 ; WX 1061 ; N uni04A6 ; B 83 -140 1065 729 ;
-C -1 ; WX 803 ; N uni04A7 ; B 70 -126 777 524 ;
-C -1 ; WX 722 ; N uni04A8 ; B 112 -23 770 741 ;
-C -1 ; WX 500 ; N uni04A9 ; B 76 -23 554 539 ;
-C -1 ; WX 722 ; N uni04AA ; B 112 -205 770 741 ;
-C -1 ; WX 500 ; N uni04AB ; B 76 -205 554 539 ;
-C -1 ; WX 611 ; N uni04AC ; B 158 -135 747 729 ;
-C -1 ; WX 400 ; N uni04AD ; B 100 -120 488 524 ;
-C -1 ; WX 667 ; N uni04AE ; B 168 0 816 729 ;
-C -1 ; WX 667 ; N uni04AF ; B 157 -200 725 524 ;
-C -1 ; WX 667 ; N uni04B0 ; B 114 0 807 729 ;
-C -1 ; WX 667 ; N uni04B1 ; B 106 -200 726 524 ;
-C -1 ; WX 665 ; N uni04B2 ; B 22 -135 792 729 ;
-C -1 ; WX 496 ; N uni04B3 ; B 17 -120 579 524 ;
-C -1 ; WX 879 ; N uni04B4 ; B 158 -135 956 729 ;
-C -1 ; WX 629 ; N uni04B5 ; B 100 -120 667 524 ;
-C -1 ; WX 642 ; N uni04B6 ; B 159 -135 691 729 ;
-C -1 ; WX 497 ; N uni04B7 ; B 133 -120 535 524 ;
-C -1 ; WX 642 ; N uni04B8 ; B 159 0 691 729 ;
-C -1 ; WX 497 ; N uni04B9 ; B 133 0 535 524 ;
-C -1 ; WX 642 ; N uni04BA ; B 159 0 691 729 ;
-C -1 ; WX 497 ; N uni04BB ; B 133 0 535 524 ;
-C -1 ; WX 722 ; N uni04BC ; B -8 -23 770 794 ;
-C -1 ; WX 605 ; N uni04BD ; B 75 -23 664 542 ;
-C -1 ; WX 722 ; N uni04BE ; B -8 -205 770 794 ;
-C -1 ; WX 605 ; N uni04BF ; B 75 -205 664 542 ;
-C -1 ; WX 278 ; N uni04C0 ; B 100 0 349 729 ;
-C -1 ; WX 897 ; N uni04C1 ; B 22 0 1024 936 ;
-C -1 ; WX 818 ; N uni04C2 ; B 17 0 901 734 ;
-C -1 ; WX 664 ; N uni04C3 ; B 79 -140 810 729 ;
-C -1 ; WX 510 ; N uni04C4 ; B 70 -126 593 524 ;
-C -1 ; WX 722 ; N uni04C7 ; B 83 -140 799 729 ;
-C -1 ; WX 561 ; N uni04C8 ; B 70 -126 599 524 ;
-C -1 ; WX 642 ; N uni04CB ; B 159 -135 691 729 ;
-C -1 ; WX 497 ; N uni04CC ; B 133 -120 535 524 ;
-C -1 ; WX 667 ; N uni04D0 ; B 17 0 687 936 ;
-C -1 ; WX 556 ; N uni04D1 ; B 65 -23 586 734 ;
-C -1 ; WX 667 ; N uni04D2 ; B 17 0 662 904 ;
-C -1 ; WX 556 ; N uni04D3 ; B 65 -23 568 702 ;
-C -1 ; WX 1000 ; N uni04D4 ; B 11 0 1087 729 ;
-C -1 ; WX 889 ; N uni04D5 ; B 59 -23 915 539 ;
-C -1 ; WX 667 ; N uni04D6 ; B 90 0 751 936 ;
-C -1 ; WX 556 ; N uni04D7 ; B 84 -23 581 734 ;
-C -1 ; WX 722 ; N uni04D8 ; B 110 -23 770 741 ;
-C -1 ; WX 495 ; N afii10846 ; B 76 -23 554 539 ;
-C -1 ; WX 722 ; N uni04DA ; B 110 -23 770 904 ;
-C -1 ; WX 495 ; N uni04DB ; B 76 -23 554 702 ;
-C -1 ; WX 897 ; N uni04DC ; B 22 0 1024 904 ;
-C -1 ; WX 818 ; N uni04DD ; B 17 0 901 702 ;
-C -1 ; WX 652 ; N uni04DE ; B 71 -23 695 904 ;
-C -1 ; WX 495 ; N uni04DF ; B 60 -23 520 702 ;
-C -1 ; WX 649 ; N uni04E0 ; B 71 -23 761 729 ;
-C -1 ; WX 492 ; N uni04E1 ; B 60 -23 546 524 ;
-C -1 ; WX 731 ; N uni04E2 ; B 83 0 808 870 ;
-C -1 ; WX 560 ; N uni04E3 ; B 70 0 598 668 ;
-C -1 ; WX 731 ; N uni04E4 ; B 83 0 808 904 ;
-C -1 ; WX 560 ; N uni04E5 ; B 70 0 598 702 ;
-C -1 ; WX 778 ; N uni04E6 ; B 104 -23 828 904 ;
-C -1 ; WX 556 ; N uni04E7 ; B 80 -23 576 702 ;
-C -1 ; WX 780 ; N uni04E8 ; B 103 -23 831 741 ;
-C -1 ; WX 554 ; N uni04E9 ; B 79 -23 575 539 ;
-C -1 ; WX 780 ; N uni04EA ; B 103 -23 831 904 ;
-C -1 ; WX 554 ; N uni04EB ; B 79 -23 575 702 ;
-C -1 ; WX 717 ; N uni04EC ; B 104 -23 767 904 ;
-C -1 ; WX 534 ; N uni04ED ; B 80 -23 554 702 ;
-C -1 ; WX 530 ; N uni04EE ; B 22 0 657 870 ;
-C -1 ; WX 500 ; N uni04EF ; B 8 -218 590 668 ;
-C -1 ; WX 530 ; N uni04F0 ; B 22 0 657 904 ;
-C -1 ; WX 500 ; N uni04F1 ; B 8 -218 590 702 ;
-C -1 ; WX 530 ; N uni04F2 ; B 22 0 673 951 ;
-C -1 ; WX 500 ; N uni04F3 ; B 8 -218 674 749 ;
-C -1 ; WX 642 ; N uni04F4 ; B 159 0 691 904 ;
-C -1 ; WX 497 ; N uni04F5 ; B 133 0 535 702 ;
-C -1 ; WX 886 ; N uni04F8 ; B 83 0 963 904 ;
-C -1 ; WX 734 ; N uni04F9 ; B 70 0 772 702 ;
-C -1 ; WX 430 ; N uniF6C4 ; B 70 0 476 524 ;
-C -1 ; WX 556 ; N uniF6C5 ; B 1 -23 555 775 ;
-C -1 ; WX 640 ; N uniF6C6 ; B -18 -120 596 524 ;
-C -1 ; WX 560 ; N uniF6C7 ; B 70 0 598 524 ;
-C -1 ; WX 400 ; N uniF6C8 ; B 100 0 488 524 ;
-C -1 ; WX 722 ; N Ccircumflex ; B 112 -23 770 979 ;
-C -1 ; WX 500 ; N ccircumflex ; B 76 -23 554 774 ;
-C -1 ; WX 722 ; N Cdotaccent ; B 112 -23 770 932 ;
-C -1 ; WX 500 ; N cdotaccent ; B 76 -23 554 727 ;
-C -1 ; WX 667 ; N Ebreve ; B 90 0 751 964 ;
-C -1 ; WX 556 ; N ebreve ; B 84 -23 592 759 ;
-C -1 ; WX 778 ; N Gcircumflex ; B 109 -23 809 979 ;
-C -1 ; WX 556 ; N gcircumflex ; B 32 -218 601 774 ;
-C -1 ; WX 778 ; N Gdotaccent ; B 109 -23 809 932 ;
-C -1 ; WX 556 ; N gdotaccent ; B 32 -218 601 727 ;
-C -1 ; WX 722 ; N Hcircumflex ; B 83 0 799 979 ;
-C -1 ; WX 556 ; N hcircumflex ; B 70 0 600 979 ;
-C -1 ; WX 772 ; N Hbar ; B 103 0 864 729 ;
-C -1 ; WX 575 ; N hbar ; B 89 0 593 729 ;
-C -1 ; WX 278 ; N Itilde ; B 100 0 505 937 ;
-C -1 ; WX 278 ; N itilde ; B 94 0 451 732 ;
-C -1 ; WX 278 ; N Ibreve ; B 100 0 503 964 ;
-C -1 ; WX 278 ; N ibreve ; B 94 0 448 759 ;
-C -1 ; WX 742 ; N IJ ; B 100 -23 812 729 ;
-C -1 ; WX 362 ; N ij ; B 66 -218 443 729 ;
-C -1 ; WX 500 ; N Jcircumflex ; B 47 -23 693 951 ;
-C -1 ; WX 222 ; N jcircumflex ; B -65 -218 387 828 ;
-C -1 ; WX 510 ; N kgreenlandic ; B 70 0 593 524 ;
-C -1 ; WX 556 ; N Ldot ; B 80 0 551 729 ;
-C -1 ; WX 500 ; N ldot ; B 68 0 445 729 ;
-C -1 ; WX 556 ; N napostrophe ; B 70 0 574 788 ;
-C -1 ; WX 722 ; N Eng ; B 76 -156 801 729 ;
-C -1 ; WX 556 ; N eng ; B 70 -126 574 539 ;
-C -1 ; WX 778 ; N Obreve ; B 104 -23 828 964 ;
-C -1 ; WX 556 ; N obreve ; B 80 -23 585 759 ;
-C -1 ; WX 667 ; N Scircumflex ; B 89 -23 714 979 ;
-C -1 ; WX 500 ; N scircumflex ; B 61 -23 521 774 ;
-C -1 ; WX 611 ; N Tbar ; B 158 0 748 729 ;
-C -1 ; WX 278 ; N tbar ; B 66 -23 366 668 ;
-C -1 ; WX 722 ; N Utilde ; B 124 -23 800 937 ;
-C -1 ; WX 556 ; N utilde ; B 88 -23 594 732 ;
-C -1 ; WX 722 ; N Ubreve ; B 124 -23 800 964 ;
-C -1 ; WX 556 ; N ubreve ; B 88 -23 594 759 ;
-C -1 ; WX 944 ; N Wcircumflex ; B 177 0 1084 979 ;
-C -1 ; WX 722 ; N wcircumflex ; B 118 0 820 774 ;
-C -1 ; WX 667 ; N Ycircumflex ; B 168 0 816 979 ;
-C -1 ; WX 500 ; N ycircumflex ; B 8 -218 590 774 ;
-C -1 ; WX 278 ; N longs ; B 89 0 413 732 ;
-C -1 ; WX 1126 ; N afii61352 ; B 76 0 1105 729 ;
-C -1 ; WX 838 ; N infinity ; B 79 119 898 547 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 996
-KPX quoteright y -14
-KPX quoteright w -5
-KPX quoteright v -10
-KPX quoteright t -14
-KPX quoteright s -23
-KPX quoteright r -24
-KPX quoteright period -68
-KPX quoteright o -31
-KPX quoteright d -25
-KPX quoteright comma -68
-KPX quoteright Aring -76
-KPX quoteright Adieresis -76
-KPX quoteright Aacute -76
-KPX quoteright AE -88
-KPX quoteright A -76
-KPX comma quoteright -55
-KPX comma quotedblright -47
-KPX comma one -105
-KPX hyphen Y -97
-KPX hyphen W -24
-KPX hyphen V -51
-KPX hyphen T -86
-KPX hyphen Aring -12
-KPX hyphen Adieresis -12
-KPX hyphen Aacute -12
-KPX hyphen AE -17
-KPX hyphen A -12
-KPX period quoteright -56
-KPX period quotedblright -48
-KPX period one -106
-KPX zero seven -50
-KPX zero one -56
-KPX zero four -11
-KPX one zero -71
-KPX one two -78
-KPX one three -75
-KPX one six -71
-KPX one seven -98
-KPX one period -82
-KPX one one -125
-KPX one nine -71
-KPX one four -88
-KPX one five -72
-KPX one eight -73
-KPX one comma -82
-KPX two seven -38
-KPX two one -45
-KPX two four -43
-KPX three seven -45
-KPX three one -57
-KPX three four -9
-KPX four seven -65
-KPX four one -88
-KPX four four -3
-KPX five seven -32
-KPX five one -83
-KPX five four -7
-KPX six seven -40
-KPX six one -52
-KPX six four -7
-KPX seven two -31
-KPX seven three -29
-KPX seven six -44
-KPX seven seven -11
-KPX seven period -123
-KPX seven one -58
-KPX seven four -95
-KPX seven five -37
-KPX seven eight -34
-KPX seven comma -123
-KPX seven colon -84
-KPX eight seven -43
-KPX eight one -55
-KPX eight four -6
-KPX nine seven -50
-KPX nine one -55
-KPX nine four -12
-KPX A y -44
-KPX A w -29
-KPX A v -40
-KPX A u -18
-KPX A t -22
-KPX A quoteright -68
-KPX A quotedblright -60
-KPX A q -15
-KPX A period -2
-KPX A o -19
-KPX A hyphen -8
-KPX A guilsinglleft -47
-KPX A guillemotleft -51
-KPX A g -17
-KPX A e -22
-KPX A d -14
-KPX A comma -4
-KPX A ccedilla -16
-KPX A c -16
-KPX A b -5
-KPX A a -16
-KPX A Y -104
-KPX A W -57
-KPX A V -81
-KPX A Ugrave -42
-KPX A Udieresis -42
-KPX A Ucircumflex -42
-KPX A Uacute -42
-KPX A U -42
-KPX A T -103
-KPX A Q -38
-KPX A Odieresis -37
-KPX A O -37
-KPX A G -41
-KPX A Ccedilla -41
-KPX A C -41
-KPX B Y -56
-KPX B W -27
-KPX B V -49
-KPX B Oslash -2
-KPX B Ograve -14
-KPX B Odieresis -14
-KPX B Ocircumflex -14
-KPX B Oacute -14
-KPX B OE -11
-KPX B O -14
-KPX B Atilde -28
-KPX B Aring -28
-KPX B Adieresis -28
-KPX B Acircumflex -28
-KPX B Aacute -28
-KPX B AE -29
-KPX B A -28
-KPX C Odieresis -18
-KPX C Oacute -18
-KPX C O -18
-KPX C K -20
-KPX C H -22
-KPX C Aring -43
-KPX C Adieresis -43
-KPX C Aacute -43
-KPX C AE -44
-KPX C A -43
-KPX D Y -74
-KPX D X -58
-KPX D W -31
-KPX D V -54
-KPX D T -56
-KPX D J -13
-KPX D Atilde -50
-KPX D Aring -50
-KPX D Agrave -50
-KPX D Adieresis -50
-KPX D Acircumflex -50
-KPX D Aacute -50
-KPX D A -50
-KPX F u -42
-KPX F r -44
-KPX F period -113
-KPX F oslash -30
-KPX F oe -33
-KPX F odieresis -30
-KPX F oacute -30
-KPX F o -30
-KPX F j -19
-KPX F i -19
-KPX F hyphen -20
-KPX F eacute -33
-KPX F e -33
-KPX F comma -113
-KPX F aring -45
-KPX F ae -41
-KPX F adieresis -45
-KPX F aacute -45
-KPX F a -45
-KPX F Odieresis -30
-KPX F O -30
-KPX F J -59
-KPX F Atilde -78
-KPX F Aring -78
-KPX F Agrave -78
-KPX F Adieresis -78
-KPX F Acircumflex -78
-KPX F Aacute -78
-KPX F A -78
-KPX G Y -72
-KPX G W -31
-KPX G V -53
-KPX G T -53
-KPX G Atilde -14
-KPX G Aring -14
-KPX G Agrave -14
-KPX G Adieresis -14
-KPX G Acircumflex -14
-KPX G Aacute -14
-KPX G AE -11
-KPX G A -14
-KPX J Aring -39
-KPX J Adieresis -39
-KPX J AE -39
-KPX J A -39
-KPX K y -76
-KPX K udieresis -32
-KPX K u -32
-KPX K odieresis -42
-KPX K oacute -42
-KPX K o -42
-KPX K hyphen -53
-KPX K e -46
-KPX K aring -23
-KPX K ae -20
-KPX K adieresis -23
-KPX K a -23
-KPX K T 14
-KPX K S -48
-KPX K Odieresis -53
-KPX K Oacute -53
-KPX K OE -49
-KPX K O -53
-KPX K G -57
-KPX K C -56
-KPX L y -68
-KPX L udieresis -17
-KPX L u -17
-KPX L quoteright -153
-KPX L quotedblright -145
-KPX L hyphen -140
-KPX L Y -128
-KPX L W -77
-KPX L V -115
-KPX L Udieresis -46
-KPX L U -46
-KPX L T -112
-KPX L S -28
-KPX L Otilde -51
-KPX L Ograve -51
-KPX L Odieresis -51
-KPX L Ocircumflex -51
-KPX L Oacute -51
-KPX L O -51
-KPX L G -53
-KPX L Ccedilla -51
-KPX L C -52
-KPX L Aring 8
-KPX L Adieresis 8
-KPX L Aacute 8
-KPX L AE 11
-KPX L A 8
-KPX N udieresis -9
-KPX N u -8
-KPX N period -15
-KPX N oslash -4
-KPX N odieresis -8
-KPX N oacute -8
-KPX N o -8
-KPX N eacute -11
-KPX N e -11
-KPX N comma -15
-KPX N aring -17
-KPX N ae -13
-KPX N adieresis -17
-KPX N aacute -17
-KPX N a -17
-KPX N Odieresis -11
-KPX N Oacute -11
-KPX N O -11
-KPX N G -14
-KPX N Ccedilla -14
-KPX N C -15
-KPX N Aring -19
-KPX N Adieresis -19
-KPX N Aacute -19
-KPX N AE -16
-KPX N A -19
-KPX O Y -71
-KPX O X -52
-KPX O W -25
-KPX O V -48
-KPX O T -54
-KPX O Aring -43
-KPX O Adieresis -43
-KPX O Aacute -43
-KPX O AE -47
-KPX O A -43
-KPX P period -138
-KPX P oslash -35
-KPX P oe -38
-KPX P odieresis -34
-KPX P oacute -34
-KPX P o -34
-KPX P hyphen -45
-KPX P eacute -38
-KPX P e -38
-KPX P comma -138
-KPX P aring -39
-KPX P ae -35
-KPX P adieresis -39
-KPX P aacute -39
-KPX P a -39
-KPX P J -85
-KPX P Aring -86
-KPX P Adieresis -86
-KPX P Aacute -86
-KPX P AE -93
-KPX P A -86
-KPX R y -16
-KPX R udieresis -14
-KPX R uacute -14
-KPX R u -13
-KPX R oe -16
-KPX R odieresis -13
-KPX R oacute -13
-KPX R o -13
-KPX R hyphen -4
-KPX R eacute -16
-KPX R e -16
-KPX R aring -21
-KPX R ae -17
-KPX R adieresis -21
-KPX R aacute -21
-KPX R a -21
-KPX R Y -54
-KPX R W -27
-KPX R V -49
-KPX R Udieresis -21
-KPX R U -21
-KPX R T -33
-KPX R Odieresis -17
-KPX R Oacute -17
-KPX R OE -14
-KPX R O -17
-KPX R G -21
-KPX R Ccedilla -21
-KPX R C -21
-KPX S t -11
-KPX S Y -58
-KPX S W -31
-KPX S V -52
-KPX S T -38
-KPX S Aring -31
-KPX S Adieresis -31
-KPX S Aacute -31
-KPX S AE -31
-KPX S A -31
-KPX T y -110
-KPX T w -103
-KPX T v -106
-KPX T u -98
-KPX T semicolon -140
-KPX T s -98
-KPX T r -98
-KPX T period -105
-KPX T oslash -94
-KPX T o -99
-KPX T j -12
-KPX T i -12
-KPX T hyphen -82
-KPX T guilsinglleft -123
-KPX T guillemotleft -126
-KPX T g -94
-KPX T e -102
-KPX T comma -105
-KPX T colon -152
-KPX T c -96
-KPX T ae -104
-KPX T a -107
-KPX T Y 10
-KPX T W 7
-KPX T V 2
-KPX T S -32
-KPX T Otilde -50
-KPX T Oslash -42
-KPX T Ograve -50
-KPX T Odieresis -50
-KPX T Ocircumflex -50
-KPX T Oacute -50
-KPX T OE -44
-KPX T O -50
-KPX T J -108
-KPX T G -55
-KPX T C -53
-KPX T Atilde -104
-KPX T Aring -104
-KPX T Agrave -104
-KPX T Adieresis -104
-KPX T Acircumflex -104
-KPX T Aacute -104
-KPX T AE -106
-KPX T A -104
-KPX U r -16
-KPX U period -32
-KPX U p -8
-KPX U n -16
-KPX U m -17
-KPX U comma -35
-KPX U Atilde -45
-KPX U Aring -45
-KPX U Adieresis -45
-KPX U Acircumflex -45
-KPX U Aacute -45
-KPX U AE -48
-KPX U A -45
-KPX V y -28
-KPX V u -52
-KPX V semicolon -75
-KPX V r -51
-KPX V period -94
-KPX V oslash -57
-KPX V o -61
-KPX V i -14
-KPX V hyphen -44
-KPX V guilsinglleft -84
-KPX V guillemotleft -88
-KPX V g -57
-KPX V e -64
-KPX V comma -94
-KPX V colon -76
-KPX V ae -66
-KPX V a -71
-KPX V T 7
-KPX V S -44
-KPX V Otilde -46
-KPX V Oslash -34
-KPX V Ograve -46
-KPX V Odieresis -46
-KPX V Ocircumflex -46
-KPX V Oacute -46
-KPX V O -46
-KPX V G -50
-KPX V C -50
-KPX V Atilde -77
-KPX V Aring -77
-KPX V Agrave -77
-KPX V Adieresis -77
-KPX V Acircumflex -77
-KPX V Aacute -77
-KPX V AE -84
-KPX V A -77
-KPX W y -15
-KPX W u -36
-KPX W semicolon -62
-KPX W r -36
-KPX W period -62
-KPX W oslash -32
-KPX W o -36
-KPX W i -10
-KPX W hyphen -19
-KPX W guilsinglleft -60
-KPX W guillemotleft -63
-KPX W g -32
-KPX W e -39
-KPX W comma -62
-KPX W colon -62
-KPX W ae -42
-KPX W a -46
-KPX W T 11
-KPX W S -31
-KPX W Otilde -26
-KPX W Oslash -14
-KPX W Ograve -26
-KPX W Odieresis -26
-KPX W Ocircumflex -26
-KPX W Oacute -26
-KPX W O -26
-KPX W G -30
-KPX W C -30
-KPX W Atilde -56
-KPX W Aring -56
-KPX W Agrave -56
-KPX W Adieresis -56
-KPX W Acircumflex -56
-KPX W Aacute -56
-KPX W AE -62
-KPX W A -56
-KPX X y -67
-KPX X u -36
-KPX X o -46
-KPX X hyphen -57
-KPX X e -51
-KPX X a -27
-KPX X Q -51
-KPX X Odieresis -50
-KPX X O -50
-KPX X C -53
-KPX Y v -48
-KPX Y u -73
-KPX Y semicolon -97
-KPX Y period -117
-KPX Y p -63
-KPX Y oslash -89
-KPX Y o -93
-KPX Y i -6
-KPX Y hyphen -89
-KPX Y guilsinglleft -124
-KPX Y guillemotleft -128
-KPX Y g -89
-KPX Y e -97
-KPX Y comma -117
-KPX Y colon -97
-KPX Y ae -95
-KPX Y a -100
-KPX Y T 15
-KPX Y S -49
-KPX Y Otilde -64
-KPX Y Oslash -55
-KPX Y Ograve -64
-KPX Y Odieresis -64
-KPX Y Ocircumflex -64
-KPX Y Oacute -64
-KPX Y O -64
-KPX Y G -69
-KPX Y C -68
-KPX Y Atilde -102
-KPX Y Aring -102
-KPX Y Agrave -102
-KPX Y Adieresis -102
-KPX Y Acircumflex -102
-KPX Y Aacute -102
-KPX Y AE -108
-KPX Y A -102
-KPX Z y -44
-KPX Z v -44
-KPX quoteleft Y -17
-KPX quoteleft W 6
-KPX quoteleft V -5
-KPX quoteleft T -14
-KPX quoteleft Aring -74
-KPX quoteleft Adieresis -74
-KPX quoteleft Aacute -74
-KPX quoteleft AE -86
-KPX quoteleft A -74
-KPX a y -33
-KPX a w -16
-KPX a v -26
-KPX a quoteright -23
-KPX a j -10
-KPX b y -28
-KPX b w -10
-KPX b v -21
-KPX c k -1
-KPX c h -7
-KPX e y -33
-KPX e x -35
-KPX e w -16
-KPX e v -26
-KPX e t -16
-KPX e quoteright -20
-KPX f t 16
-KPX f s -8
-KPX f quoteright -8
-KPX f oslash -16
-KPX f oe -20
-KPX f odieresis -18
-KPX f oacute -18
-KPX f o -18
-KPX f l -12
-KPX f j -11
-KPX f i -10
-KPX f f 12
-KPX f eacute -21
-KPX f e -21
-KPX f aring -20
-KPX f ae -15
-KPX f adieresis -20
-KPX f aacute -20
-KPX f a -20
-KPX g r -9
-KPX g odieresis -8
-KPX g oacute -8
-KPX g l -8
-KPX g eacute -11
-KPX g e -11
-KPX g aring -17
-KPX g ae -13
-KPX g adieresis -17
-KPX g a -17
-KPX h y -31
-KPX h quoteright -19
-KPX i j -10
-KPX i T -16
-KPX k udieresis -16
-KPX k u -22
-KPX k s -14
-KPX k period -13
-KPX k odieresis -30
-KPX k oacute -30
-KPX k o -30
-KPX k hyphen -49
-KPX k g -26
-KPX k eacute -33
-KPX k e -33
-KPX k comma -13
-KPX k aring -14
-KPX k ae -12
-KPX k adieresis -14
-KPX k aacute -14
-KPX k a -14
-KPX l y -15
-KPX l v -11
-KPX m y -30
-KPX m w -14
-KPX m v -24
-KPX m p -3
-KPX n y -31
-KPX n w -14
-KPX n v -24
-KPX n quoteright -19
-KPX n p -3
-KPX n T -103
-KPX o y -34
-KPX o x -35
-KPX o w -16
-KPX o v -27
-KPX o t -17
-KPX o quoteright -23
-KPX o T -106
-KPX p y -28
-KPX p t -10
-KPX q u -5
-KPX q c -2
-KPX r y 15
-KPX r x 9
-KPX r w 21
-KPX r v 18
-KPX r u -7
-KPX r t 21
-KPX r semicolon -30
-KPX r s -4
-KPX r r -8
-KPX r quoteright -6
-KPX r q -10
-KPX r period -77
-KPX r oslash -14
-KPX r ograve -14
-KPX r oe -16
-KPX r odieresis -14
-KPX r ocircumflex -14
-KPX r oacute -14
-KPX r o -14
-KPX r n -8
-KPX r m -9
-KPX r l -7
-KPX r k -2
-KPX r j -6
-KPX r i -6
-KPX r hyphen -54
-KPX r h -8
-KPX r g -8
-KPX r f 17
-KPX r egrave -17
-KPX r ecircumflex -17
-KPX r eacute -17
-KPX r e -17
-KPX r d -8
-KPX r comma -77
-KPX r colon -31
-KPX r ccedilla -11
-KPX r c -11
-KPX r aring -16
-KPX r agrave -16
-KPX r ae -11
-KPX r adieresis -16
-KPX r acircumflex -16
-KPX r aacute -16
-KPX r a -16
-KPX s t -15
-KPX s quoteright -24
-KPX t semicolon -36
-KPX t quoteright -7
-KPX t odieresis -19
-KPX t oacute -19
-KPX t o -19
-KPX t h -14
-KPX t eacute -22
-KPX t e -22
-KPX t colon -37
-KPX t aring -10
-KPX t ae -7
-KPX t adieresis -10
-KPX t aacute -10
-KPX t a -10
-KPX t S -17
-KPX u quoteright -14
-KPX v semicolon -31
-KPX v s -17
-KPX v period -76
-KPX v oslash -25
-KPX v ograve -25
-KPX v odieresis -25
-KPX v oacute -25
-KPX v o -25
-KPX v l -8
-KPX v hyphen -19
-KPX v g -20
-KPX v egrave -29
-KPX v ecircumflex -29
-KPX v eacute -29
-KPX v e -29
-KPX v comma -76
-KPX v colon -32
-KPX v c -22
-KPX v atilde -30
-KPX v aring -30
-KPX v agrave -30
-KPX v ae -25
-KPX v adieresis -30
-KPX v acircumflex -30
-KPX v aacute -30
-KPX v a -30
-KPX w semicolon -31
-KPX w s -14
-KPX w period -57
-KPX w oslash -14
-KPX w ograve -17
-KPX w odieresis -17
-KPX w oacute -17
-KPX w o -17
-KPX w l -8
-KPX w hyphen -8
-KPX w g -13
-KPX w egrave -20
-KPX w ecircumflex -20
-KPX w eacute -20
-KPX w e -20
-KPX w comma -57
-KPX w colon -32
-KPX w c -14
-KPX w atilde -26
-KPX w aring -26
-KPX w agrave -26
-KPX w ae -22
-KPX w adieresis -26
-KPX w acircumflex -26
-KPX w aacute -26
-KPX w a -26
-KPX x q -28
-KPX x o -33
-KPX x eacute -36
-KPX x e -36
-KPX x c -30
-KPX x a -30
-KPX y semicolon -40
-KPX y s -23
-KPX y period -80
-KPX y oslash -30
-KPX y ograve -31
-KPX y odieresis -31
-KPX y oacute -31
-KPX y o -31
-KPX y l -14
-KPX y hyphen -24
-KPX y g -26
-KPX y egrave -35
-KPX y ecircumflex -35
-KPX y eacute -35
-KPX y e -35
-KPX y comma -80
-KPX y colon -40
-KPX y c -28
-KPX y atilde -36
-KPX y aring -36
-KPX y agrave -36
-KPX y ae -31
-KPX y adieresis -36
-KPX y acircumflex -36
-KPX y aacute -36
-KPX y a -36
-KPX quotedblleft Y -1
-KPX quotedblleft W 22
-KPX quotedblleft V 10
-KPX quotedblleft T 1
-KPX quotedblleft Aring -58
-KPX quotedblleft Adieresis -58
-KPX quotedblleft Aacute -58
-KPX quotedblleft AE -70
-KPX quotedblleft A -58
-KPX guilsinglright Y -131
-KPX guilsinglright W -62
-KPX guilsinglright V -90
-KPX guilsinglright T -126
-KPX guilsinglright Aring -52
-KPX guilsinglright Adieresis -52
-KPX guilsinglright Aacute -52
-KPX guilsinglright AE -56
-KPX guilsinglright A -52
-KPX quotedblbase Y -96
-KPX quotedblbase W -39
-KPX quotedblbase V -74
-KPX quotedblbase T -80
-KPX quotedblbase AE 21
-KPX quotedblbase A 21
-KPX quotedblright Y -2
-KPX quotedblright W 21
-KPX quotedblright V 9
-KPX quotedblright T 2
-KPX quotedblright Aring -60
-KPX quotedblright Adieresis -60
-KPX quotedblright Aacute -60
-KPX quotedblright AE -72
-KPX quotedblright A -60
-KPX guillemotright Y -137
-KPX guillemotright W -68
-KPX guillemotright V -96
-KPX guillemotright T -132
-KPX guillemotright Aring -58
-KPX guillemotright Adieresis -58
-KPX guillemotright Aacute -58
-KPX guillemotright AE -62
-KPX guillemotright A -58
-KPX Oslash A -47
-KPX ae y -32
-KPX ae w -15
-KPX ae v -26
-KPX Adieresis y -44
-KPX Adieresis w -29
-KPX Adieresis v -40
-KPX Adieresis u -19
-KPX Adieresis t -22
-KPX Adieresis quoteright -68
-KPX Adieresis quotedblright -60
-KPX Adieresis q -15
-KPX Adieresis period -3
-KPX Adieresis o -19
-KPX Adieresis hyphen -8
-KPX Adieresis guilsinglleft -48
-KPX Adieresis guillemotleft -51
-KPX Adieresis g -17
-KPX Adieresis d -14
-KPX Adieresis comma -4
-KPX Adieresis c -17
-KPX Adieresis b -5
-KPX Adieresis a -16
-KPX Adieresis Y -104
-KPX Adieresis W -57
-KPX Adieresis V -81
-KPX Adieresis U -43
-KPX Adieresis T -103
-KPX Adieresis Q -39
-KPX Adieresis O -38
-KPX Adieresis G -41
-KPX Adieresis C -42
-KPX Aacute y -44
-KPX Aacute w -29
-KPX Aacute v -40
-KPX Aacute u -20
-KPX Aacute t -23
-KPX Aacute quoteright -68
-KPX Aacute q -16
-KPX Aacute period -3
-KPX Aacute o -20
-KPX Aacute hyphen -9
-KPX Aacute guilsinglleft -48
-KPX Aacute guillemotleft -51
-KPX Aacute g -17
-KPX Aacute e -23
-KPX Aacute d -15
-KPX Aacute comma -4
-KPX Aacute c -17
-KPX Aacute b -6
-KPX Aacute a -16
-KPX Aacute Y -104
-KPX Aacute W -57
-KPX Aacute V -81
-KPX Aacute U -43
-KPX Aacute T -103
-KPX Aacute Q -39
-KPX Aacute O -38
-KPX Aacute G -42
-KPX Aacute C -42
-KPX Agrave period -2
-KPX Agrave comma -4
-KPX Agrave Y -104
-KPX Agrave W -57
-KPX Agrave V -81
-KPX Agrave U -42
-KPX Agrave T -103
-KPX Agrave Q -38
-KPX Agrave O -37
-KPX Agrave G -41
-KPX Agrave C -41
-KPX Acircumflex period -2
-KPX Acircumflex comma -4
-KPX Acircumflex Y -104
-KPX Acircumflex W -57
-KPX Acircumflex V -81
-KPX Acircumflex U -42
-KPX Acircumflex T -103
-KPX Acircumflex Q -38
-KPX Acircumflex O -37
-KPX Acircumflex G -41
-KPX Acircumflex C -41
-KPX Atilde period -4
-KPX Atilde comma -4
-KPX Atilde Y -104
-KPX Atilde W -57
-KPX Atilde V -81
-KPX Atilde U -44
-KPX Atilde T -103
-KPX Atilde Q -40
-KPX Atilde O -39
-KPX Atilde G -42
-KPX Atilde C -43
-KPX Aring y -44
-KPX Aring w -29
-KPX Aring v -40
-KPX Aring u -18
-KPX Aring t -22
-KPX Aring quoteright -68
-KPX Aring quotedblright -60
-KPX Aring q -15
-KPX Aring period -2
-KPX Aring o -19
-KPX Aring hyphen -8
-KPX Aring guilsinglleft -47
-KPX Aring guillemotleft -51
-KPX Aring g -17
-KPX Aring e -22
-KPX Aring d -14
-KPX Aring comma -4
-KPX Aring c -16
-KPX Aring b -5
-KPX Aring a -16
-KPX Aring Y -104
-KPX Aring W -57
-KPX Aring V -81
-KPX Aring U -42
-KPX Aring T -103
-KPX Aring Q -38
-KPX Aring O -37
-KPX Aring G -41
-KPX Aring C -41
-KPX Ccedilla A -44
-KPX Odieresis Y -71
-KPX Odieresis X -52
-KPX Odieresis W -25
-KPX Odieresis V -48
-KPX Odieresis T -54
-KPX Odieresis A -43
-KPX Oacute Y -71
-KPX Oacute W -25
-KPX Oacute V -48
-KPX Oacute T -54
-KPX Oacute A -43
-KPX Ograve Y -71
-KPX Ograve V -48
-KPX Ograve T -54
-KPX Ocircumflex Y -71
-KPX Ocircumflex V -48
-KPX Ocircumflex T -54
-KPX Otilde Y -71
-KPX Otilde V -48
-KPX Otilde T -54
-KPX Udieresis r -16
-KPX Udieresis period -32
-KPX Udieresis p -8
-KPX Udieresis n -16
-KPX Udieresis m -17
-KPX Udieresis comma -35
-KPX Udieresis b -8
-KPX Udieresis A -44
-KPX Uacute r -16
-KPX Uacute period -32
-KPX Uacute p -8
-KPX Uacute n -16
-KPX Uacute m -17
-KPX Uacute comma -35
-KPX Uacute A -45
-KPX Ugrave A -45
-KPX Ucircumflex A -45
-KPX adieresis y -33
-KPX adieresis w -16
-KPX adieresis v -26
-KPX aacute y -33
-KPX aacute w -16
-KPX aacute v -26
-KPX agrave y -33
-KPX agrave w -16
-KPX agrave v -26
-KPX aring y -33
-KPX aring w -16
-KPX aring v -26
-KPX eacute y -33
-KPX eacute w -16
-KPX eacute v -26
-KPX ecircumflex y -33
-KPX ecircumflex w -16
-KPX ecircumflex v -26
-KPX odieresis y -34
-KPX odieresis x -35
-KPX odieresis w -16
-KPX odieresis v -27
-KPX odieresis t -17
-KPX oacute y -34
-KPX oacute w -16
-KPX oacute v -27
-KPX ograve y -34
-KPX ograve w -16
-KPX ograve v -27
-KPX ocircumflex t -17
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-sans-l/n019023l.pfb b/src/fonts/nimbus-sans-l/n019023l.pfb
deleted file mode 100644
index 66467fb..0000000
--- a/src/fonts/nimbus-sans-l/n019023l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019023l.pfm b/src/fonts/nimbus-sans-l/n019023l.pfm
deleted file mode 100644
index 99ecf57..0000000
--- a/src/fonts/nimbus-sans-l/n019023l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019024l.afm b/src/fonts/nimbus-sans-l/n019024l.afm
deleted file mode 100644
index f4225a0..0000000
--- a/src/fonts/nimbus-sans-l/n019024l.afm
+++ /dev/null
@@ -1,1577 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 14:36:47 2007
-FontName NimbusSanL-BoldItal
-FullName Nimbus Sans L Bold Italic
-FamilyName Nimbus Sans L
-Weight Bold
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle -12
-IsFixedPitch false
-UnderlinePosition -111
-UnderlineThickness 69
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -177 -309 1199 953
-CapHeight 729
-XHeight 540
-Ascender 729
-Descender -218
-StartCharMetrics 562
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 112 0 417 726 ;
-C 34 ; WX 474 ; N quotedbl ; B 177 470 579 729 ;
-C 35 ; WX 556 ; N numbersign ; B 33 -32 660 697 ;
-C 36 ; WX 556 ; N dollar ; B 59 -126 628 763 ;
-C 37 ; WX 889 ; N percent ; B 129 -20 903 709 ;
-C 38 ; WX 722 ; N ampersand ; B 89 -23 720 723 ;
-C 39 ; WX 278 ; N quoteright ; B 165 469 356 729 ;
-C 40 ; WX 333 ; N parenleft ; B 84 -200 458 729 ;
-C 41 ; WX 333 ; N parenright ; B -21 -200 356 729 ;
-C 42 ; WX 389 ; N asterisk ; B 145 407 478 729 ;
-C 43 ; WX 584 ; N plus ; B 87 -10 596 473 ;
-C 44 ; WX 278 ; N comma ; B 27 -174 245 146 ;
-C 45 ; WX 333 ; N hyphen ; B 70 207 371 342 ;
-C 46 ; WX 278 ; N period ; B 64 0 245 146 ;
-C 47 ; WX 278 ; N slash ; B -1 -14 427 714 ;
-C 48 ; WX 556 ; N zero ; B 81 -23 614 724 ;
-C 49 ; WX 556 ; N one ; B 172 0 529 709 ;
-C 50 ; WX 556 ; N two ; B 30 0 628 724 ;
-C 51 ; WX 556 ; N three ; B 67 -23 613 724 ;
-C 52 ; WX 556 ; N four ; B 57 0 599 709 ;
-C 53 ; WX 556 ; N five ; B 59 -23 641 709 ;
-C 54 ; WX 556 ; N six ; B 85 -23 625 724 ;
-C 55 ; WX 556 ; N seven ; B 131 0 679 709 ;
-C 56 ; WX 556 ; N eight ; B 60 -23 620 724 ;
-C 57 ; WX 556 ; N nine ; B 68 -23 611 724 ;
-C 58 ; WX 333 ; N colon ; B 113 0 374 520 ;
-C 59 ; WX 333 ; N semicolon ; B 76 -174 374 520 ;
-C 60 ; WX 584 ; N less ; B 77 -10 630 474 ;
-C 61 ; WX 584 ; N equal ; B 61 52 622 412 ;
-C 62 ; WX 584 ; N greater ; B 38 -10 591 474 ;
-C 63 ; WX 611 ; N question ; B 168 0 672 744 ;
-C 64 ; WX 975 ; N at ; B 73 -137 1032 745 ;
-C 65 ; WX 722 ; N A ; B 26 0 703 729 ;
-C 66 ; WX 722 ; N B ; B 82 0 762 729 ;
-C 67 ; WX 722 ; N C ; B 107 -23 793 741 ;
-C 68 ; WX 722 ; N D ; B 77 0 776 729 ;
-C 69 ; WX 667 ; N E ; B 79 0 762 729 ;
-C 70 ; WX 611 ; N F ; B 74 0 741 729 ;
-C 71 ; WX 778 ; N G ; B 107 -23 819 741 ;
-C 72 ; WX 722 ; N H ; B 68 0 812 729 ;
-C 73 ; WX 278 ; N I ; B 63 0 368 729 ; L J IJ ;
-C 74 ; WX 556 ; N J ; B 59 -23 641 729 ;
-C 75 ; WX 722 ; N K ; B 74 0 843 729 ;
-C 76 ; WX 611 ; N L ; B 80 0 606 729 ; L periodcentered Ldot ;
-C 77 ; WX 833 ; N M ; B 66 0 931 729 ;
-C 78 ; WX 722 ; N N ; B 68 0 816 729 ; L o afii61352 ;
-C 79 ; WX 778 ; N O ; B 106 -23 828 741 ;
-C 80 ; WX 667 ; N P ; B 76 0 747 729 ;
-C 81 ; WX 778 ; N Q ; B 109 -54 831 741 ;
-C 82 ; WX 722 ; N R ; B 80 0 785 729 ;
-C 83 ; WX 667 ; N S ; B 76 -23 725 741 ;
-C 84 ; WX 611 ; N T ; B 142 0 753 729 ; L M trademark ;
-C 85 ; WX 722 ; N U ; B 119 -23 809 729 ;
-C 86 ; WX 667 ; N V ; B 179 0 802 729 ;
-C 87 ; WX 944 ; N W ; B 168 0 1087 729 ;
-C 88 ; WX 667 ; N X ; B 22 0 802 729 ;
-C 89 ; WX 667 ; N Y ; B 182 0 805 729 ;
-C 90 ; WX 611 ; N Z ; B 30 0 733 729 ;
-C 91 ; WX 333 ; N bracketleft ; B 23 -200 463 729 ;
-C 92 ; WX 278 ; N backslash ; B 138 -23 285 709 ;
-C 93 ; WX 333 ; N bracketright ; B -25 -200 415 729 ;
-C 94 ; WX 584 ; N asciicircum ; B 119 270 580 695 ;
-C 95 ; WX 556 ; N underscore ; B -65 -145 550 -76 ;
-C 96 ; WX 278 ; N quoteleft ; B 167 469 357 729 ;
-C 97 ; WX 556 ; N a ; B 50 -23 578 549 ;
-C 98 ; WX 611 ; N b ; B 59 -23 640 729 ;
-C 99 ; WX 556 ; N c ; B 77 -23 597 549 ;
-C 100 ; WX 611 ; N d ; B 79 -23 700 729 ;
-C 101 ; WX 556 ; N e ; B 64 -23 591 549 ;
-C 102 ; WX 333 ; N f ; B 90 0 464 729 ; L l fl ; L i fi ;
-C 103 ; WX 611 ; N g ; B 26 -218 656 549 ;
-C 104 ; WX 611 ; N h ; B 67 0 629 729 ;
-C 105 ; WX 278 ; N i ; B 67 0 362 729 ; L j ij ;
-C 106 ; WX 278 ; N j ; B -43 -218 365 729 ;
-C 107 ; WX 556 ; N k ; B 59 0 651 729 ;
-C 108 ; WX 278 ; N l ; B 67 0 362 729 ; L periodcentered ldot ;
-C 109 ; WX 889 ; N m ; B 60 0 911 549 ;
-C 110 ; WX 611 ; N n ; B 63 0 629 549 ;
-C 111 ; WX 611 ; N o ; B 82 -23 634 549 ;
-C 112 ; WX 611 ; N p ; B 11 -218 637 549 ;
-C 113 ; WX 611 ; N q ; B 72 -218 659 549 ;
-C 114 ; WX 389 ; N r ; B 63 0 487 549 ;
-C 115 ; WX 556 ; N s ; B 60 -23 589 549 ;
-C 116 ; WX 333 ; N t ; B 101 -23 414 674 ;
-C 117 ; WX 611 ; N u ; B 88 -23 656 540 ;
-C 118 ; WX 556 ; N v ; B 129 0 651 540 ;
-C 119 ; WX 778 ; N w ; B 120 0 881 540 ;
-C 120 ; WX 556 ; N x ; B 16 0 648 540 ;
-C 121 ; WX 556 ; N y ; B 37 -219 653 540 ;
-C 122 ; WX 500 ; N z ; B 21 0 575 540 ;
-C 123 ; WX 389 ; N braceleft ; B 84 -200 472 729 ;
-C 124 ; WX 280 ; N bar ; B 57 -200 335 729 ;
-C 125 ; WX 389 ; N braceright ; B 29 -200 419 729 ;
-C 126 ; WX 584 ; N asciitilde ; B 97 142 581 314 ;
-C 161 ; WX 333 ; N exclamdown ; B 26 -186 331 540 ;
-C 162 ; WX 556 ; N cent ; B 79 -124 598 634 ;
-C 163 ; WX 556 ; N sterling ; B 49 -23 629 715 ;
-C 164 ; WX 167 ; N fraction ; B -177 -20 489 715 ;
-C 165 ; WX 556 ; N yen ; B 107 0 702 704 ;
-C 166 ; WX 556 ; N florin ; B -21 -220 690 744 ;
-C 167 ; WX 556 ; N section ; B 56 -201 596 723 ;
-C 168 ; WX 556 ; N currency ; B 66 100 644 604 ;
-C 169 ; WX 238 ; N quotesingle ; B 177 470 343 729 ;
-C 170 ; WX 500 ; N quotedblleft ; B 171 469 588 729 ;
-C 171 ; WX 556 ; N guillemotleft ; B 135 72 571 481 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 128 72 351 481 ;
-C 173 ; WX 333 ; N guilsinglright ; B 96 72 319 481 ;
-C 174 ; WX 611 ; N fi ; B 85 0 703 729 ;
-C 175 ; WX 611 ; N fl ; B 88 0 701 729 ;
-C 177 ; WX 556 ; N endash ; B 35 207 624 311 ;
-C 178 ; WX 556 ; N dagger ; B 109 -194 626 709 ;
-C 179 ; WX 556 ; N daggerdbl ; B 35 -194 623 709 ;
-C 180 ; WX 278 ; N periodcentered ; B 143 182 270 282 ;
-C 182 ; WX 556 ; N paragraph ; B 121 -191 684 729 ;
-C 183 ; WX 350 ; N bullet ; B 111 175 367 425 ;
-C 184 ; WX 278 ; N quotesinglbase ; B 37 -135 228 125 ;
-C 185 ; WX 500 ; N quotedblbase ; B 37 -135 462 125 ;
-C 186 ; WX 500 ; N quotedblright ; B 173 469 595 729 ;
-C 187 ; WX 556 ; N guillemotright ; B 103 72 533 481 ;
-C 188 ; WX 1000 ; N ellipsis ; B 92 0 939 146 ;
-C 189 ; WX 1000 ; N perthousand ; B 72 -21 1021 739 ;
-C 191 ; WX 611 ; N questiondown ; B 52 -204 556 540 ;
-C 193 ; WX 333 ; N grave ; B 175 607 339 757 ;
-C 194 ; WX 333 ; N acute ; B 247 607 475 757 ;
-C 195 ; WX 333 ; N circumflex ; B 135 610 453 757 ;
-C 196 ; WX 333 ; N tilde ; B 117 622 500 744 ;
-C 197 ; WX 333 ; N macron ; B 150 642 467 722 ;
-C 198 ; WX 333 ; N breve ; B 188 611 455 754 ;
-C 199 ; WX 333 ; N dotaccent ; B 241 621 377 741 ;
-C 200 ; WX 333 ; N dieresis ; B 147 621 469 741 ;
-C 202 ; WX 333 ; N ring ; B 214 593 398 773 ;
-C 203 ; WX 333 ; N cedilla ; B -13 -220 270 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 82 610 498 757 ;
-C 206 ; WX 333 ; N ogonek ; B 23 -233 248 0 ;
-C 207 ; WX 333 ; N caron ; B 167 610 485 757 ;
-C 208 ; WX 1000 ; N emdash ; B 37 207 1070 311 ;
-C 225 ; WX 1000 ; N AE ; B 1 0 1104 729 ;
-C 227 ; WX 370 ; N ordfeminine ; B 96 262 451 729 ;
-C 232 ; WX 611 ; N Lslash ; B 54 0 624 729 ;
-C 233 ; WX 778 ; N Oslash ; B 34 -39 906 749 ;
-C 234 ; WX 1000 ; N OE ; B 90 -23 1107 741 ;
-C 235 ; WX 365 ; N ordmasculine ; B 92 262 471 729 ;
-C 241 ; WX 889 ; N ae ; B 54 -23 927 549 ;
-C 245 ; WX 278 ; N dotlessi ; B 67 0 322 540 ;
-C 248 ; WX 278 ; N lslash ; B 50 0 372 729 ;
-C 249 ; WX 611 ; N oslash ; B 12 -38 709 557 ;
-C 250 ; WX 944 ; N oe ; B 71 -23 986 549 ;
-C 251 ; WX 611 ; N germandbls ; B 67 -23 654 729 ;
-C -1 ; WX 722 ; N Adieresis ; B 26 0 708 920 ;
-C -1 ; WX 722 ; N Aacute ; B 26 0 714 936 ;
-C -1 ; WX 722 ; N Agrave ; B 26 0 703 936 ;
-C -1 ; WX 722 ; N Acircumflex ; B 26 0 703 936 ;
-C -1 ; WX 722 ; N Abreve ; B 26 0 703 934 ;
-C -1 ; WX 722 ; N Atilde ; B 26 0 739 923 ;
-C -1 ; WX 722 ; N Aring ; B 26 0 703 953 ;
-C -1 ; WX 722 ; N Aogonek ; B 26 -233 703 729 ;
-C -1 ; WX 722 ; N Ccedilla ; B 107 -220 793 741 ;
-C -1 ; WX 722 ; N Cacute ; B 107 -23 793 936 ;
-C -1 ; WX 722 ; N Ccaron ; B 107 -23 793 936 ;
-C -1 ; WX 722 ; N Dcaron ; B 77 0 776 936 ;
-C -1 ; WX 667 ; N Edieresis ; B 79 0 762 920 ;
-C -1 ; WX 667 ; N Eacute ; B 79 0 762 936 ;
-C -1 ; WX 667 ; N Egrave ; B 79 0 762 936 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 79 0 762 936 ;
-C -1 ; WX 667 ; N Ecaron ; B 79 0 762 936 ;
-C -1 ; WX 667 ; N Edotaccent ; B 79 0 762 918 ;
-C -1 ; WX 667 ; N Eogonek ; B 79 -233 762 729 ;
-C -1 ; WX 778 ; N Gbreve ; B 107 -23 819 934 ;
-C -1 ; WX 278 ; N Idieresis ; B 63 0 483 920 ;
-C -1 ; WX 278 ; N Iacute ; B 63 0 489 936 ;
-C -1 ; WX 278 ; N Igrave ; B 63 0 368 936 ;
-C -1 ; WX 278 ; N Icircumflex ; B 63 0 467 936 ;
-C -1 ; WX 278 ; N Idotaccent ; B 63 0 388 918 ;
-C -1 ; WX 611 ; N Lacute ; B 80 0 606 936 ;
-C -1 ; WX 611 ; N Lcaron ; B 80 0 607 729 ;
-C -1 ; WX 722 ; N Nacute ; B 68 0 816 936 ;
-C -1 ; WX 722 ; N Ncaron ; B 68 0 816 936 ;
-C -1 ; WX 722 ; N Ntilde ; B 68 0 816 923 ;
-C -1 ; WX 778 ; N Odieresis ; B 106 -23 828 920 ;
-C -1 ; WX 778 ; N Oacute ; B 106 -23 828 936 ;
-C -1 ; WX 778 ; N Ograve ; B 106 -23 828 936 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 106 -23 828 936 ;
-C -1 ; WX 778 ; N Otilde ; B 106 -23 828 923 ;
-C -1 ; WX 778 ; N Ohungarumlaut ; B 106 -23 841 936 ;
-C -1 ; WX 722 ; N Racute ; B 80 0 785 936 ;
-C -1 ; WX 722 ; N Rcaron ; B 80 0 785 936 ;
-C -1 ; WX 667 ; N Sacute ; B 76 -23 725 936 ;
-C -1 ; WX 667 ; N Scaron ; B 76 -23 725 936 ;
-C -1 ; WX 667 ; N Scedilla ; B 76 -220 725 741 ;
-C -1 ; WX 611 ; N Tcaron ; B 142 0 753 936 ;
-C -1 ; WX 722 ; N Udieresis ; B 119 -23 809 920 ;
-C -1 ; WX 722 ; N Uacute ; B 119 -23 809 936 ;
-C -1 ; WX 722 ; N Ugrave ; B 119 -23 809 936 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 119 -23 809 936 ;
-C -1 ; WX 722 ; N Uring ; B 119 -23 809 953 ;
-C -1 ; WX 722 ; N Uhungarumlaut ; B 119 -23 809 936 ;
-C -1 ; WX 667 ; N Yacute ; B 182 0 805 936 ;
-C -1 ; WX 611 ; N Zacute ; B 30 0 733 936 ;
-C -1 ; WX 611 ; N Zcaron ; B 30 0 733 936 ;
-C -1 ; WX 611 ; N Zdotaccent ; B 30 0 733 918 ;
-C -1 ; WX 722 ; N Amacron ; B 26 0 706 901 ;
-C -1 ; WX 611 ; N Tcommaaccent ; B 142 -307 753 729 ;
-C -1 ; WX 667 ; N Ydieresis ; B 182 0 805 920 ;
-C -1 ; WX 667 ; N Emacron ; B 79 0 762 901 ;
-C -1 ; WX 278 ; N Imacron ; B 63 0 466 901 ;
-C -1 ; WX 278 ; N Iogonek ; B 7 -233 368 729 ;
-C -1 ; WX 722 ; N Kcommaaccent ; B 74 -307 843 729 ;
-C -1 ; WX 611 ; N Lcommaaccent ; B 80 -309 606 729 ;
-C -1 ; WX 722 ; N Ncommaaccent ; B 68 -307 816 729 ;
-C -1 ; WX 778 ; N Omacron ; B 106 -23 828 901 ;
-C -1 ; WX 722 ; N Rcommaaccent ; B 80 -307 785 729 ;
-C -1 ; WX 778 ; N Gcommaaccent ; B 107 -307 819 741 ;
-C -1 ; WX 722 ; N Umacron ; B 119 -23 809 901 ;
-C -1 ; WX 722 ; N Uogonek ; B 119 -233 809 729 ;
-C -1 ; WX 556 ; N adieresis ; B 50 -23 581 741 ;
-C -1 ; WX 556 ; N aacute ; B 50 -23 587 757 ;
-C -1 ; WX 556 ; N agrave ; B 50 -23 578 757 ;
-C -1 ; WX 556 ; N acircumflex ; B 50 -23 578 757 ;
-C -1 ; WX 556 ; N abreve ; B 50 -23 578 754 ;
-C -1 ; WX 556 ; N atilde ; B 50 -23 612 744 ;
-C -1 ; WX 556 ; N aring ; B 50 -23 578 773 ;
-C -1 ; WX 556 ; N aogonek ; B 50 -233 578 549 ;
-C -1 ; WX 556 ; N cacute ; B 77 -23 597 757 ;
-C -1 ; WX 556 ; N ccaron ; B 77 -23 607 757 ;
-C -1 ; WX 556 ; N ccedilla ; B 77 -220 597 549 ;
-C -1 ; WX 722 ; N dcaron ; B 79 -23 882 729 ;
-C -1 ; WX 556 ; N edieresis ; B 64 -23 591 741 ;
-C -1 ; WX 556 ; N eacute ; B 64 -23 591 757 ;
-C -1 ; WX 556 ; N egrave ; B 64 -23 591 757 ;
-C -1 ; WX 556 ; N ecircumflex ; B 64 -23 591 757 ;
-C -1 ; WX 556 ; N ecaron ; B 64 -23 593 757 ;
-C -1 ; WX 556 ; N edotaccent ; B 64 -23 591 741 ;
-C -1 ; WX 556 ; N eogonek ; B 64 -233 591 549 ;
-C -1 ; WX 611 ; N gbreve ; B 26 -218 656 754 ;
-C -1 ; WX 278 ; N idieresis ; B 67 0 442 741 ;
-C -1 ; WX 278 ; N iacute ; B 67 0 448 757 ;
-C -1 ; WX 278 ; N igrave ; B 67 0 322 757 ;
-C -1 ; WX 278 ; N icircumflex ; B 67 0 426 757 ;
-C -1 ; WX 278 ; N lacute ; B 67 0 474 936 ;
-C -1 ; WX 384 ; N lcaron ; B 67 0 544 729 ;
-C -1 ; WX 611 ; N nacute ; B 63 0 629 757 ;
-C -1 ; WX 611 ; N ncaron ; B 63 0 629 757 ;
-C -1 ; WX 611 ; N ntilde ; B 63 0 646 744 ;
-C -1 ; WX 611 ; N odieresis ; B 82 -23 634 741 ;
-C -1 ; WX 611 ; N oacute ; B 82 -23 634 757 ;
-C -1 ; WX 611 ; N ograve ; B 82 -23 634 757 ;
-C -1 ; WX 611 ; N ocircumflex ; B 82 -23 634 757 ;
-C -1 ; WX 611 ; N otilde ; B 82 -23 639 744 ;
-C -1 ; WX 611 ; N ohungarumlaut ; B 82 -23 710 757 ;
-C -1 ; WX 389 ; N racute ; B 63 0 500 757 ;
-C -1 ; WX 556 ; N sacute ; B 60 -23 589 757 ;
-C -1 ; WX 556 ; N scaron ; B 60 -23 597 757 ;
-C -1 ; WX 556 ; N scommaaccent ; B 60 -307 589 549 ;
-C -1 ; WX 404 ; N tcaron ; B 101 -23 578 829 ;
-C -1 ; WX 611 ; N udieresis ; B 88 -23 656 741 ;
-C -1 ; WX 611 ; N uacute ; B 88 -23 656 757 ;
-C -1 ; WX 611 ; N ugrave ; B 88 -23 656 757 ;
-C -1 ; WX 611 ; N ucircumflex ; B 88 -23 656 757 ;
-C -1 ; WX 611 ; N uring ; B 88 -23 656 773 ;
-C -1 ; WX 611 ; N uhungarumlaut ; B 88 -23 697 757 ;
-C -1 ; WX 556 ; N yacute ; B 37 -219 653 757 ;
-C -1 ; WX 500 ; N zacute ; B 21 0 575 757 ;
-C -1 ; WX 500 ; N zcaron ; B 21 0 575 757 ;
-C -1 ; WX 500 ; N zdotaccent ; B 21 0 575 741 ;
-C -1 ; WX 556 ; N ydieresis ; B 37 -219 653 741 ;
-C -1 ; WX 333 ; N tcommaaccent ; B 62 -307 414 674 ;
-C -1 ; WX 556 ; N amacron ; B 50 -23 579 722 ;
-C -1 ; WX 556 ; N emacron ; B 64 -23 591 722 ;
-C -1 ; WX 278 ; N imacron ; B 67 0 424 722 ;
-C -1 ; WX 556 ; N kcommaaccent ; B 59 -307 651 729 ;
-C -1 ; WX 278 ; N lcommaaccent ; B 11 -307 362 729 ;
-C -1 ; WX 611 ; N ncommaaccent ; B 63 -307 629 549 ;
-C -1 ; WX 611 ; N omacron ; B 82 -23 634 722 ;
-C -1 ; WX 389 ; N rcommaaccent ; B 8 -307 487 549 ;
-C -1 ; WX 611 ; N umacron ; B 88 -23 656 722 ;
-C -1 ; WX 611 ; N uogonek ; B 88 -233 656 540 ;
-C -1 ; WX 389 ; N rcaron ; B 63 0 533 757 ;
-C -1 ; WX 556 ; N scedilla ; B 60 -220 589 549 ;
-C -1 ; WX 611 ; N gcommaaccent ; B 26 -218 656 854 ;
-C -1 ; WX 268 ; N iogonek ; B 0 -233 351 729 ;
-C -1 ; WX 667 ; N Scommaaccent ; B 76 -307 725 741 ;
-C -1 ; WX 722 ; N Eth ; B 73 0 776 729 ;
-C -1 ; WX 722 ; N Dcroat ; B 73 0 776 729 ;
-C -1 ; WX 667 ; N Thorn ; B 76 0 721 729 ;
-C -1 ; WX 611 ; N dcroat ; B 79 -23 746 729 ;
-C -1 ; WX 611 ; N eth ; B 83 -23 633 744 ;
-C -1 ; WX 611 ; N thorn ; B 11 -218 637 729 ;
-C -1 ; WX 556 ; N Euro ; B 21 -23 648 724 ;
-C -1 ; WX 444 ; N onesuperior ; B 210 284 438 709 ;
-C -1 ; WX 444 ; N twosuperior ; B 124 284 499 718 ;
-C -1 ; WX 444 ; N threesuperior ; B 147 271 490 718 ;
-C -1 ; WX 606 ; N degree ; B 240 383 543 686 ;
-C -1 ; WX 584 ; N minus ; B 77 172 606 292 ;
-C -1 ; WX 584 ; N multiply ; B 102 18 582 444 ;
-C -1 ; WX 584 ; N divide ; B 77 0 606 462 ;
-C -1 ; WX 1000 ; N trademark ; B 213 273 1087 729 ;
-C -1 ; WX 584 ; N plusminus ; B 50 0 630 633 ;
-C -1 ; WX 1055 ; N onehalf ; B 210 -20 1050 715 ;
-C -1 ; WX 1055 ; N onequarter ; B 210 -20 1032 715 ;
-C -1 ; WX 1055 ; N threequarters ; B 147 -20 1032 718 ;
-C -1 ; WX 333 ; N commaaccent ; B 43 -307 217 -60 ;
-C -1 ; WX 737 ; N copyright ; B 54 -22 837 743 ;
-C -1 ; WX 737 ; N registered ; B 55 -22 837 743 ;
-C -1 ; WX 489 ; N lozenge ; B 95 0 541 744 ;
-C -1 ; WX 729 ; N Delta ; B 8 0 721 729 ;
-C -1 ; WX 584 ; N notequal ; B 61 -74 622 544 ;
-C -1 ; WX 542 ; N radical ; B 102 -36 705 913 ;
-C -1 ; WX 584 ; N lessequal ; B 35 0 657 624 ;
-C -1 ; WX 584 ; N greaterequal ; B 44 0 627 624 ;
-C -1 ; WX 584 ; N logicalnot ; B 103 86 632 376 ;
-C -1 ; WX 711 ; N summation ; B -18 -97 760 760 ;
-C -1 ; WX 490 ; N partialdiff ; B 22 -15 458 750 ;
-C -1 ; WX 280 ; N brokenbar ; B 57 -200 335 729 ;
-C -1 ; WX 611 ; N mu ; B 11 -220 655 540 ;
-C -1 ; WX 722 ; N afii10017 ; B 26 0 703 729 ;
-C -1 ; WX 722 ; N afii10018 ; B 82 0 749 729 ;
-C -1 ; WX 723 ; N afii10019 ; B 82 0 763 729 ;
-C -1 ; WX 611 ; N afii10020 ; B 74 0 741 729 ;
-C -1 ; WX 918 ; N afii10021 ; B -50 -150 851 729 ;
-C -1 ; WX 666 ; N afii10022 ; B 79 0 761 729 ;
-C -1 ; WX 666 ; N afii10023 ; B 79 0 761 922 ;
-C -1 ; WX 1054 ; N afii10024 ; B 22 0 1189 729 ;
-C -1 ; WX 659 ; N afii10025 ; B 67 -23 716 741 ;
-C -1 ; WX 722 ; N afii10026 ; B 68 0 816 729 ;
-C -1 ; WX 722 ; N afii10027 ; B 68 0 816 944 ;
-C -1 ; WX 720 ; N afii10028 ; B 74 0 841 729 ;
-C -1 ; WX 722 ; N afii10029 ; B -31 0 734 729 ;
-C -1 ; WX 843 ; N afii10030 ; B 68 0 933 729 ;
-C -1 ; WX 722 ; N afii10031 ; B 68 0 812 729 ;
-C -1 ; WX 778 ; N afii10032 ; B 106 -23 829 741 ;
-C -1 ; WX 722 ; N afii10033 ; B 68 0 812 729 ;
-C -1 ; WX 649 ; N afii10034 ; B 68 0 739 729 ;
-C -1 ; WX 837 ; N afii10035 ; B 106 -23 787 741 ;
-C -1 ; WX 611 ; N afii10036 ; B 142 0 753 729 ;
-C -1 ; WX 698 ; N afii10037 ; B 136 0 833 729 ;
-C -1 ; WX 902 ; N afii10038 ; B 23 0 873 729 ;
-C -1 ; WX 664 ; N afii10039 ; B 22 0 774 729 ;
-C -1 ; WX 730 ; N afii10040 ; B 68 -150 820 729 ;
-C -1 ; WX 671 ; N afii10041 ; B 161 0 761 729 ;
-C -1 ; WX 1101 ; N afii10042 ; B 68 0 1191 729 ;
-C -1 ; WX 1179 ; N afii10043 ; B 68 -150 1199 729 ;
-C -1 ; WX 816 ; N afii10044 ; B 142 0 856 729 ;
-C -1 ; WX 939 ; N afii10045 ; B 66 0 1037 729 ;
-C -1 ; WX 639 ; N afii10046 ; B 66 0 679 729 ;
-C -1 ; WX 737 ; N afii10047 ; B 106 -23 787 741 ;
-C -1 ; WX 1087 ; N afii10048 ; B 66 -23 1138 741 ;
-C -1 ; WX 690 ; N afii10049 ; B 22 0 788 729 ;
-C -1 ; WX 554 ; N afii10065 ; B 51 -23 576 549 ;
-C -1 ; WX 611 ; N afii10066 ; B 76 -23 687 777 ;
-C -1 ; WX 616 ; N afii10067 ; B 60 0 602 540 ;
-C -1 ; WX 475 ; N afii10068 ; B 60 0 523 540 ;
-C -1 ; WX 804 ; N afii10069 ; B -22 -125 732 540 ;
-C -1 ; WX 552 ; N afii10070 ; B 64 -23 587 549 ;
-C -1 ; WX 552 ; N afii10071 ; B 64 -23 587 729 ;
-C -1 ; WX 775 ; N afii10072 ; B 16 0 867 540 ;
-C -1 ; WX 556 ; N afii10073 ; B 56 -23 580 549 ;
-C -1 ; WX 636 ; N afii10074 ; B 60 0 658 540 ;
-C -1 ; WX 636 ; N afii10075 ; B 60 0 658 754 ;
-C -1 ; WX 529 ; N afii10076 ; B 59 0 624 540 ;
-C -1 ; WX 608 ; N afii10077 ; B -28 0 600 540 ;
-C -1 ; WX 697 ; N afii10078 ; B 60 0 719 540 ;
-C -1 ; WX 636 ; N afii10079 ; B 60 0 658 540 ;
-C -1 ; WX 611 ; N afii10080 ; B 82 -23 635 549 ;
-C -1 ; WX 636 ; N afii10081 ; B 60 0 658 540 ;
-C -1 ; WX 611 ; N afii10082 ; B -24 -218 604 549 ;
-C -1 ; WX 554 ; N afii10083 ; B 77 -23 595 549 ;
-C -1 ; WX 454 ; N afii10084 ; B 101 0 535 540 ;
-C -1 ; WX 552 ; N afii10085 ; B 37 -219 639 540 ;
-C -1 ; WX 989 ; N afii10086 ; B 72 -218 982 719 ;
-C -1 ; WX 554 ; N afii10087 ; B 16 0 641 540 ;
-C -1 ; WX 662 ; N afii10088 ; B 60 -125 684 540 ;
-C -1 ; WX 606 ; N afii10089 ; B 127 0 628 540 ;
-C -1 ; WX 934 ; N afii10090 ; B 60 0 956 540 ;
-C -1 ; WX 960 ; N afii10091 ; B 60 -125 982 540 ;
-C -1 ; WX 674 ; N afii10092 ; B 100 0 684 540 ;
-C -1 ; WX 814 ; N afii10093 ; B 60 0 836 540 ;
-C -1 ; WX 557 ; N afii10094 ; B 60 0 567 540 ;
-C -1 ; WX 575 ; N afii10095 ; B 82 -23 597 549 ;
-C -1 ; WX 888 ; N afii10096 ; B 60 -23 911 549 ;
-C -1 ; WX 636 ; N afii10097 ; B 37 0 658 540 ;
-C -1 ; WX 666 ; N uni0400 ; B 79 0 761 951 ;
-C -1 ; WX 807 ; N afii10051 ; B 142 -166 814 729 ;
-C -1 ; WX 611 ; N afii10052 ; B 74 0 741 951 ;
-C -1 ; WX 737 ; N afii10053 ; B 106 -23 787 741 ;
-C -1 ; WX 667 ; N afii10054 ; B -2 -23 647 741 ;
-C -1 ; WX 278 ; N afii10055 ; B -14 0 290 729 ;
-C -1 ; WX 278 ; N afii10056 ; B -14 0 404 921 ;
-C -1 ; WX 556 ; N afii10057 ; B -17 -23 566 729 ;
-C -1 ; WX 1031 ; N afii10058 ; B -31 0 1043 729 ;
-C -1 ; WX 1088 ; N afii10059 ; B -9 0 1043 729 ;
-C -1 ; WX 787 ; N afii10060 ; B 142 0 794 729 ;
-C -1 ; WX 720 ; N afii10061 ; B 74 0 841 951 ;
-C -1 ; WX 722 ; N uni040D ; B 68 0 816 951 ;
-C -1 ; WX 698 ; N afii10062 ; B 136 0 833 944 ;
-C -1 ; WX 722 ; N afii10145 ; B 6 -150 751 729 ;
-C -1 ; WX 552 ; N uni0450 ; B 64 -23 587 759 ;
-C -1 ; WX 611 ; N afii10099 ; B 67 -132 625 729 ;
-C -1 ; WX 475 ; N afii10100 ; B 60 0 557 759 ;
-C -1 ; WX 575 ; N afii10101 ; B 82 -23 597 549 ;
-C -1 ; WX 556 ; N afii10102 ; B 2 -23 531 549 ;
-C -1 ; WX 278 ; N afii10103 ; B 67 0 362 729 ;
-C -1 ; WX 278 ; N afii10104 ; B 67 0 441 729 ;
-C -1 ; WX 278 ; N afii10105 ; B -43 -218 365 729 ;
-C -1 ; WX 860 ; N afii10106 ; B -28 0 863 540 ;
-C -1 ; WX 823 ; N afii10107 ; B 6 0 840 540 ;
-C -1 ; WX 611 ; N afii10108 ; B 67 0 625 729 ;
-C -1 ; WX 529 ; N afii10109 ; B 59 0 624 759 ;
-C -1 ; WX 636 ; N uni045D ; B 60 0 658 759 ;
-C -1 ; WX 552 ; N afii10110 ; B 37 -219 639 752 ;
-C -1 ; WX 608 ; N afii10193 ; B 16 -125 615 540 ;
-C -1 ; WX 639 ; N uni048C ; B 66 0 679 729 ;
-C -1 ; WX 619 ; N uni048D ; B 60 0 552 540 ;
-C -1 ; WX 649 ; N uni048E ; B 68 0 740 729 ;
-C -1 ; WX 611 ; N uni048F ; B -24 -218 604 549 ;
-C -1 ; WX 611 ; N afii10050 ; B -18 0 678 864 ;
-C -1 ; WX 454 ; N afii10098 ; B -7 0 483 666 ;
-C -1 ; WX 611 ; N uni0492 ; B 74 0 741 729 ;
-C -1 ; WX 475 ; N uni0493 ; B 34 0 523 540 ;
-C -1 ; WX 611 ; N uni0494 ; B 74 -166 741 729 ;
-C -1 ; WX 475 ; N uni0495 ; B 60 -132 523 540 ;
-C -1 ; WX 1054 ; N uni0496 ; B 22 -150 1189 729 ;
-C -1 ; WX 775 ; N uni0497 ; B 16 -125 867 540 ;
-C -1 ; WX 659 ; N uni0498 ; B 67 -233 716 741 ;
-C -1 ; WX 556 ; N uni0499 ; B 56 -233 580 549 ;
-C -1 ; WX 720 ; N uni049A ; B 74 -150 841 729 ;
-C -1 ; WX 529 ; N uni049B ; B 59 -125 624 540 ;
-C -1 ; WX 720 ; N uni049C ; B 74 0 841 729 ;
-C -1 ; WX 529 ; N uni049D ; B 59 0 624 540 ;
-C -1 ; WX 720 ; N uni049E ; B 74 0 841 729 ;
-C -1 ; WX 529 ; N uni049F ; B 59 0 624 540 ;
-C -1 ; WX 889 ; N uni04A0 ; B 142 0 1010 729 ;
-C -1 ; WX 650 ; N uni04A1 ; B 100 0 745 540 ;
-C -1 ; WX 722 ; N uni04A2 ; B 68 -150 812 729 ;
-C -1 ; WX 636 ; N uni04A3 ; B 60 -125 674 540 ;
-C -1 ; WX 992 ; N uni04A4 ; B 68 0 1122 729 ;
-C -1 ; WX 807 ; N uni04A5 ; B 60 0 855 540 ;
-C -1 ; WX 1067 ; N uni04A6 ; B 68 -166 1107 729 ;
-C -1 ; WX 876 ; N uni04A7 ; B 60 -132 862 540 ;
-C -1 ; WX 837 ; N uni04A8 ; B 106 -23 787 741 ;
-C -1 ; WX 554 ; N uni04A9 ; B 77 -27 595 549 ;
-C -1 ; WX 837 ; N uni04AA ; B 106 -233 787 741 ;
-C -1 ; WX 554 ; N uni04AB ; B 77 -233 595 549 ;
-C -1 ; WX 611 ; N uni04AC ; B 142 -150 753 729 ;
-C -1 ; WX 454 ; N uni04AD ; B 101 -125 535 540 ;
-C -1 ; WX 667 ; N uni04AE ; B 182 0 805 729 ;
-C -1 ; WX 667 ; N uni04AF ; B 160 -189 723 540 ;
-C -1 ; WX 667 ; N uni04B0 ; B 102 0 805 729 ;
-C -1 ; WX 667 ; N uni04B1 ; B 94 -189 723 540 ;
-C -1 ; WX 664 ; N uni04B2 ; B 22 -150 799 729 ;
-C -1 ; WX 554 ; N uni04B3 ; B 16 -125 646 540 ;
-C -1 ; WX 864 ; N uni04B4 ; B 142 -150 954 729 ;
-C -1 ; WX 727 ; N uni04B5 ; B 101 -125 749 540 ;
-C -1 ; WX 743 ; N uni04B6 ; B 161 -150 769 729 ;
-C -1 ; WX 606 ; N uni04B7 ; B 127 -125 654 540 ;
-C -1 ; WX 671 ; N uni04B8 ; B 161 0 761 729 ;
-C -1 ; WX 606 ; N uni04B9 ; B 127 0 628 540 ;
-C -1 ; WX 671 ; N uni04BA ; B 161 0 761 729 ;
-C -1 ; WX 606 ; N uni04BB ; B 127 0 628 540 ;
-C -1 ; WX 837 ; N uni04BC ; B -79 -23 787 758 ;
-C -1 ; WX 552 ; N uni04BD ; B -62 -23 587 549 ;
-C -1 ; WX 837 ; N uni04BE ; B -79 -233 787 758 ;
-C -1 ; WX 552 ; N uni04BF ; B -62 -233 587 549 ;
-C -1 ; WX 278 ; N uni04C0 ; B 63 0 368 729 ;
-C -1 ; WX 1054 ; N uni04C1 ; B 22 0 1189 944 ;
-C -1 ; WX 775 ; N uni04C2 ; B 16 0 867 752 ;
-C -1 ; WX 720 ; N uni04C3 ; B 74 -163 841 729 ;
-C -1 ; WX 529 ; N uni04C4 ; B 59 -132 624 540 ;
-C -1 ; WX 722 ; N uni04C7 ; B 68 -166 812 729 ;
-C -1 ; WX 636 ; N uni04C8 ; B 60 -132 658 540 ;
-C -1 ; WX 671 ; N uni04CB ; B 161 -150 761 729 ;
-C -1 ; WX 606 ; N uni04CC ; B 127 -125 628 540 ;
-C -1 ; WX 722 ; N uni04D0 ; B 26 0 703 944 ;
-C -1 ; WX 554 ; N uni04D1 ; B 51 -23 576 752 ;
-C -1 ; WX 722 ; N uni04D2 ; B 26 0 712 921 ;
-C -1 ; WX 554 ; N uni04D3 ; B 51 -23 576 729 ;
-C -1 ; WX 1000 ; N uni04D4 ; B 1 0 1104 729 ;
-C -1 ; WX 889 ; N uni04D5 ; B 54 -23 927 549 ;
-C -1 ; WX 666 ; N uni04D6 ; B 79 0 761 944 ;
-C -1 ; WX 552 ; N uni04D7 ; B 64 -23 587 752 ;
-C -1 ; WX 837 ; N uni04D8 ; B 101 -23 787 741 ;
-C -1 ; WX 552 ; N afii10846 ; B 64 -23 587 549 ;
-C -1 ; WX 837 ; N uni04DA ; B 101 -23 787 921 ;
-C -1 ; WX 552 ; N uni04DB ; B 64 -23 587 729 ;
-C -1 ; WX 1054 ; N uni04DC ; B 22 0 1189 921 ;
-C -1 ; WX 775 ; N uni04DD ; B 16 0 867 729 ;
-C -1 ; WX 659 ; N uni04DE ; B 67 -23 716 921 ;
-C -1 ; WX 556 ; N uni04DF ; B 56 -23 584 729 ;
-C -1 ; WX 659 ; N uni04E0 ; B 67 -23 779 729 ;
-C -1 ; WX 556 ; N uni04E1 ; B 56 -23 623 540 ;
-C -1 ; WX 722 ; N uni04E2 ; B 68 0 816 881 ;
-C -1 ; WX 636 ; N uni04E3 ; B 60 0 658 689 ;
-C -1 ; WX 722 ; N uni04E4 ; B 68 0 816 921 ;
-C -1 ; WX 636 ; N uni04E5 ; B 60 0 658 729 ;
-C -1 ; WX 778 ; N uni04E6 ; B 106 -23 829 921 ;
-C -1 ; WX 611 ; N uni04E7 ; B 82 -23 635 729 ;
-C -1 ; WX 778 ; N uni04E8 ; B 106 -23 829 741 ;
-C -1 ; WX 611 ; N uni04E9 ; B 81 -23 635 549 ;
-C -1 ; WX 778 ; N uni04EA ; B 106 -23 829 921 ;
-C -1 ; WX 611 ; N uni04EB ; B 81 -23 635 729 ;
-C -1 ; WX 737 ; N uni04EC ; B 106 -23 787 921 ;
-C -1 ; WX 575 ; N uni04ED ; B 82 -23 597 729 ;
-C -1 ; WX 698 ; N uni04EE ; B 136 0 833 881 ;
-C -1 ; WX 552 ; N uni04EF ; B 37 -219 639 689 ;
-C -1 ; WX 698 ; N uni04F0 ; B 136 0 833 921 ;
-C -1 ; WX 552 ; N uni04F1 ; B 37 -219 639 729 ;
-C -1 ; WX 698 ; N uni04F2 ; B 136 0 833 948 ;
-C -1 ; WX 552 ; N uni04F3 ; B 37 -219 686 756 ;
-C -1 ; WX 671 ; N uni04F4 ; B 161 0 761 921 ;
-C -1 ; WX 606 ; N uni04F5 ; B 127 0 628 729 ;
-C -1 ; WX 939 ; N uni04F8 ; B 66 0 1037 921 ;
-C -1 ; WX 814 ; N uni04F9 ; B 60 0 836 729 ;
-C -1 ; WX 475 ; N uniF6C4 ; B 60 0 523 540 ;
-C -1 ; WX 611 ; N uniF6C5 ; B 76 -23 687 777 ;
-C -1 ; WX 804 ; N uniF6C6 ; B -22 -125 732 540 ;
-C -1 ; WX 636 ; N uniF6C7 ; B 60 0 658 540 ;
-C -1 ; WX 454 ; N uniF6C8 ; B 101 0 535 540 ;
-C -1 ; WX 722 ; N Ccircumflex ; B 107 -23 793 948 ;
-C -1 ; WX 556 ; N ccircumflex ; B 77 -23 597 756 ;
-C -1 ; WX 722 ; N Cdotaccent ; B 107 -23 793 921 ;
-C -1 ; WX 556 ; N cdotaccent ; B 77 -23 597 729 ;
-C -1 ; WX 667 ; N Ebreve ; B 79 0 762 944 ;
-C -1 ; WX 556 ; N ebreve ; B 64 -23 591 752 ;
-C -1 ; WX 778 ; N Gcircumflex ; B 107 -23 819 948 ;
-C -1 ; WX 611 ; N gcircumflex ; B 26 -218 656 756 ;
-C -1 ; WX 778 ; N Gdotaccent ; B 107 -23 819 921 ;
-C -1 ; WX 611 ; N gdotaccent ; B 26 -218 656 729 ;
-C -1 ; WX 722 ; N Hcircumflex ; B 68 0 812 948 ;
-C -1 ; WX 611 ; N hcircumflex ; B 67 0 633 936 ;
-C -1 ; WX 762 ; N Hbar ; B 88 0 882 729 ;
-C -1 ; WX 611 ; N hbar ; B 67 0 629 729 ;
-C -1 ; WX 278 ; N Itilde ; B 63 0 513 923 ;
-C -1 ; WX 278 ; N itilde ; B 67 0 472 731 ;
-C -1 ; WX 278 ; N Ibreve ; B 63 0 469 944 ;
-C -1 ; WX 278 ; N ibreve ; B 67 0 428 752 ;
-C -1 ; WX 782 ; N IJ ; B 63 -23 876 729 ;
-C -1 ; WX 476 ; N ij ; B 67 -218 575 729 ;
-C -1 ; WX 556 ; N Jcircumflex ; B 59 -23 741 948 ;
-C -1 ; WX 278 ; N jcircumflex ; B -43 -218 442 862 ;
-C -1 ; WX 529 ; N kgreenlandic ; B 59 0 624 540 ;
-C -1 ; WX 611 ; N Ldot ; B 80 0 606 729 ;
-C -1 ; WX 556 ; N ldot ; B 67 0 518 729 ;
-C -1 ; WX 611 ; N napostrophe ; B 63 0 629 840 ;
-C -1 ; WX 722 ; N Eng ; B 68 -166 816 729 ;
-C -1 ; WX 611 ; N eng ; B 63 -132 629 549 ;
-C -1 ; WX 778 ; N Obreve ; B 106 -23 828 944 ;
-C -1 ; WX 611 ; N obreve ; B 82 -23 634 752 ;
-C -1 ; WX 667 ; N Scircumflex ; B 76 -23 725 948 ;
-C -1 ; WX 556 ; N scircumflex ; B 60 -23 589 756 ;
-C -1 ; WX 611 ; N Tbar ; B 142 0 753 729 ;
-C -1 ; WX 333 ; N tbar ; B 66 -23 414 674 ;
-C -1 ; WX 722 ; N Utilde ; B 119 -23 809 923 ;
-C -1 ; WX 611 ; N utilde ; B 88 -23 656 731 ;
-C -1 ; WX 722 ; N Ubreve ; B 119 -23 809 944 ;
-C -1 ; WX 611 ; N ubreve ; B 88 -23 656 752 ;
-C -1 ; WX 944 ; N Wcircumflex ; B 168 0 1087 948 ;
-C -1 ; WX 778 ; N wcircumflex ; B 120 0 881 756 ;
-C -1 ; WX 667 ; N Ycircumflex ; B 182 0 805 948 ;
-C -1 ; WX 556 ; N ycircumflex ; B 37 -219 653 756 ;
-C -1 ; WX 333 ; N longs ; B 90 0 464 729 ;
-C -1 ; WX 1112 ; N afii61352 ; B 68 0 1139 729 ;
-C -1 ; WX 884 ; N infinity ; B 92 105 940 579 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 989
-KPX quoteright y -9
-KPX quoteright w -4
-KPX quoteright v -11
-KPX quoteright t -11
-KPX quoteright s -27
-KPX quoteright r -20
-KPX quoteright period -51
-KPX quoteright o -34
-KPX quoteright d -30
-KPX quoteright comma -53
-KPX quoteright Aring -80
-KPX quoteright Adieresis -80
-KPX quoteright Aacute -80
-KPX quoteright AE -72
-KPX quoteright A -80
-KPX comma quoteright -35
-KPX comma quotedblright -39
-KPX comma one -79
-KPX hyphen Y -71
-KPX hyphen W -15
-KPX hyphen V -34
-KPX hyphen T -64
-KPX hyphen Aring -7
-KPX hyphen Adieresis -7
-KPX hyphen Aacute -7
-KPX hyphen AE 2
-KPX hyphen A -7
-KPX period quoteright -35
-KPX period quotedblright -39
-KPX period one -80
-KPX zero seven -21
-KPX zero one -29
-KPX zero four -3
-KPX one zero -44
-KPX one two -56
-KPX one three -53
-KPX one six -48
-KPX one seven -72
-KPX one period -49
-KPX one one -92
-KPX one nine -47
-KPX one four -70
-KPX one five -50
-KPX one eight -47
-KPX one comma -51
-KPX two seven -12
-KPX two one -24
-KPX two four -16
-KPX three seven -19
-KPX three one -34
-KPX three four -2
-KPX four seven -33
-KPX four one -55
-KPX five seven -17
-KPX five one -37
-KPX five four -3
-KPX six seven -13
-KPX six one -29
-KPX six four -1
-KPX seven two -11
-KPX seven three -7
-KPX seven six -21
-KPX seven seven 2
-KPX seven period -94
-KPX seven one -21
-KPX seven four -70
-KPX seven five -28
-KPX seven eight -10
-KPX seven comma -95
-KPX seven colon -71
-KPX eight seven -15
-KPX eight one -32
-KPX eight four 2
-KPX nine seven -23
-KPX nine one -30
-KPX nine four -6
-KPX A y -41
-KPX A w -28
-KPX A v -42
-KPX A u -17
-KPX A t -21
-KPX A quoteright -67
-KPX A quotedblright -71
-KPX A q -13
-KPX A period 13
-KPX A o -19
-KPX A hyphen 2
-KPX A guilsinglleft -44
-KPX A guillemotleft -48
-KPX A g -20
-KPX A e -10
-KPX A d -17
-KPX A comma 9
-KPX A ccedilla -17
-KPX A c -17
-KPX A b -10
-KPX A a -11
-KPX A Y -96
-KPX A W -57
-KPX A V -74
-KPX A Ugrave -37
-KPX A Udieresis -37
-KPX A Ucircumflex -37
-KPX A Uacute -37
-KPX A U -37
-KPX A T -91
-KPX A Q -39
-KPX A Odieresis -37
-KPX A O -37
-KPX A G -38
-KPX A Ccedilla -36
-KPX A C -36
-KPX B Y -63
-KPX B W -30
-KPX B V -46
-KPX B Oslash -17
-KPX B Ograve -18
-KPX B Odieresis -18
-KPX B Ocircumflex -18
-KPX B Oacute -18
-KPX B OE -9
-KPX B O -18
-KPX B Atilde -41
-KPX B Aring -41
-KPX B Adieresis -41
-KPX B Acircumflex -41
-KPX B Aacute -41
-KPX B AE -30
-KPX B A -41
-KPX C Odieresis -12
-KPX C Oacute -12
-KPX C O -12
-KPX C K -4
-KPX C H -1
-KPX C Aring -34
-KPX C Adieresis -34
-KPX C Aacute -34
-KPX C AE -23
-KPX C A -34
-KPX D Y -62
-KPX D X -40
-KPX D W -20
-KPX D V -37
-KPX D T -24
-KPX D J -4
-KPX D Atilde -40
-KPX D Aring -40
-KPX D Agrave -40
-KPX D Adieresis -40
-KPX D Acircumflex -40
-KPX D Aacute -40
-KPX D A -40
-KPX F u -32
-KPX F r -35
-KPX F period -82
-KPX F oslash -24
-KPX F oe -16
-KPX F odieresis -21
-KPX F oacute -21
-KPX F o -21
-KPX F j -17
-KPX F i -15
-KPX F hyphen 4
-KPX F eacute -12
-KPX F e -12
-KPX F comma -84
-KPX F aring -23
-KPX F ae -26
-KPX F adieresis -23
-KPX F aacute -23
-KPX F a -23
-KPX F Odieresis -24
-KPX F O -24
-KPX F J -33
-KPX F Atilde -68
-KPX F Aring -68
-KPX F Agrave -68
-KPX F Adieresis -68
-KPX F Acircumflex -68
-KPX F Aacute -68
-KPX F A -68
-KPX G Y -65
-KPX G W -25
-KPX G V -41
-KPX G T -28
-KPX G Atilde -17
-KPX G Aring -17
-KPX G Agrave -17
-KPX G Adieresis -17
-KPX G Acircumflex -17
-KPX G Aacute -17
-KPX G AE -5
-KPX G A -17
-KPX J Aring -38
-KPX J Adieresis -38
-KPX J AE -29
-KPX J A -38
-KPX K y -74
-KPX K udieresis -35
-KPX K u -35
-KPX K odieresis -45
-KPX K oacute -45
-KPX K o -45
-KPX K hyphen -52
-KPX K e -38
-KPX K aring -17
-KPX K ae -17
-KPX K adieresis -17
-KPX K a -17
-KPX K T 5
-KPX K S -45
-KPX K Odieresis -60
-KPX K Oacute -60
-KPX K OE -51
-KPX K O -60
-KPX K G -61
-KPX K C -59
-KPX L y -64
-KPX L udieresis -17
-KPX L u -17
-KPX L quoteright -143
-KPX L quotedblright -147
-KPX L hyphen -20
-KPX L Y -121
-KPX L W -79
-KPX L V -102
-KPX L Udieresis -35
-KPX L U -35
-KPX L T -104
-KPX L S -14
-KPX L Otilde -39
-KPX L Ograve -39
-KPX L Odieresis -39
-KPX L Ocircumflex -39
-KPX L Oacute -39
-KPX L O -39
-KPX L G -40
-KPX L Ccedilla -36
-KPX L C -35
-KPX L AE 12
-KPX N udieresis 4
-KPX N u 4
-KPX N period 8
-KPX N oslash 2
-KPX N odieresis 1
-KPX N oacute 1
-KPX N o 1
-KPX N eacute 10
-KPX N e 10
-KPX N comma 7
-KPX N aring 5
-KPX N ae 4
-KPX N adieresis 5
-KPX N aacute 5
-KPX N a 5
-KPX N Odieresis -2
-KPX N Oacute -2
-KPX N O -2
-KPX N G -2
-KPX N Ccedilla -1
-KPX N C -1
-KPX N Aring -15
-KPX N Adieresis -15
-KPX N Aacute -15
-KPX N AE -2
-KPX N A -15
-KPX O Y -65
-KPX O X -43
-KPX O W -24
-KPX O V -40
-KPX O T -32
-KPX O Aring -42
-KPX O Adieresis -42
-KPX O Aacute -42
-KPX O AE -33
-KPX O A -42
-KPX P period -101
-KPX P oslash -26
-KPX P oe -17
-KPX P odieresis -22
-KPX P oacute -22
-KPX P o -22
-KPX P hyphen -7
-KPX P eacute -13
-KPX P e -13
-KPX P comma -103
-KPX P aring -14
-KPX P ae -15
-KPX P adieresis -14
-KPX P aacute -14
-KPX P a -14
-KPX P J -52
-KPX P Aring -71
-KPX P Adieresis -71
-KPX P Aacute -71
-KPX P AE -62
-KPX P A -71
-KPX R y -4
-KPX R udieresis -6
-KPX R uacute -6
-KPX R u -6
-KPX R oe -4
-KPX R odieresis -9
-KPX R oacute -9
-KPX R o -9
-KPX R hyphen 10
-KPX R aring -4
-KPX R ae -5
-KPX R adieresis -4
-KPX R aacute -4
-KPX R a -4
-KPX R Y -50
-KPX R W -22
-KPX R V -38
-KPX R Udieresis -12
-KPX R U -12
-KPX R T -12
-KPX R Odieresis -13
-KPX R Oacute -13
-KPX R OE -3
-KPX R O -13
-KPX R G -13
-KPX R Ccedilla -12
-KPX R C -12
-KPX S t -4
-KPX S Y -54
-KPX S W -20
-KPX S V -36
-KPX S T -15
-KPX S Aring -26
-KPX S Adieresis -26
-KPX S Aacute -26
-KPX S AE -14
-KPX S A -26
-KPX T y -89
-KPX T w -85
-KPX T v -91
-KPX T u -78
-KPX T semicolon -105
-KPX T s -81
-KPX T r -76
-KPX T period -73
-KPX T oslash -80
-KPX T o -81
-KPX T j -11
-KPX T i -9
-KPX T hyphen -53
-KPX T guilsinglleft -103
-KPX T guillemotleft -107
-KPX T g -79
-KPX T e -72
-KPX T comma -75
-KPX T colon -104
-KPX T c -79
-KPX T ae -78
-KPX T a -77
-KPX T Y 7
-KPX T W 15
-KPX T V 9
-KPX T S -7
-KPX T Otilde -30
-KPX T Oslash -36
-KPX T Ograve -30
-KPX T Odieresis -30
-KPX T Ocircumflex -30
-KPX T Oacute -30
-KPX T OE -20
-KPX T O -30
-KPX T J -95
-KPX T G -30
-KPX T C -29
-KPX T Atilde -93
-KPX T Aring -93
-KPX T Agrave -93
-KPX T Adieresis -93
-KPX T Acircumflex -93
-KPX T Aacute -93
-KPX T AE -85
-KPX T A -93
-KPX U r -5
-KPX U period -12
-KPX U p -3
-KPX U n -5
-KPX U m -3
-KPX U comma -17
-KPX U Atilde -40
-KPX U Aring -40
-KPX U Adieresis -40
-KPX U Acircumflex -40
-KPX U Aacute -40
-KPX U AE -30
-KPX U A -40
-KPX V y -19
-KPX V u -42
-KPX V semicolon -77
-KPX V r -43
-KPX V period -74
-KPX V oslash -55
-KPX V o -56
-KPX V i -13
-KPX V hyphen -26
-KPX V guilsinglleft -77
-KPX V guillemotleft -81
-KPX V g -54
-KPX V e -46
-KPX V comma -76
-KPX V colon -74
-KPX V ae -52
-KPX V a -51
-KPX V T 12
-KPX V S -31
-KPX V Otilde -44
-KPX V Oslash -42
-KPX V Ograve -44
-KPX V Odieresis -44
-KPX V Ocircumflex -44
-KPX V Oacute -44
-KPX V O -44
-KPX V G -44
-KPX V C -43
-KPX V Atilde -75
-KPX V Aring -75
-KPX V Agrave -75
-KPX V Adieresis -75
-KPX V Acircumflex -75
-KPX V Aacute -75
-KPX V AE -65
-KPX V A -75
-KPX W y -9
-KPX W u -32
-KPX W semicolon -63
-KPX W r -33
-KPX W period -51
-KPX W oslash -37
-KPX W o -38
-KPX W i -9
-KPX W hyphen -9
-KPX W guilsinglleft -59
-KPX W guillemotleft -63
-KPX W g -36
-KPX W e -28
-KPX W comma -53
-KPX W colon -61
-KPX W ae -34
-KPX W a -34
-KPX W T 16
-KPX W S -22
-KPX W Otilde -29
-KPX W Oslash -27
-KPX W Ograve -29
-KPX W Odieresis -29
-KPX W Ocircumflex -29
-KPX W Oacute -29
-KPX W O -29
-KPX W G -29
-KPX W C -28
-KPX W Atilde -59
-KPX W Aring -59
-KPX W Agrave -59
-KPX W Adieresis -59
-KPX W Acircumflex -59
-KPX W Aacute -59
-KPX W AE -50
-KPX W A -59
-KPX X y -48
-KPX X u -35
-KPX X o -43
-KPX X hyphen -33
-KPX X e -33
-KPX X a -17
-KPX X Q -43
-KPX X Odieresis -40
-KPX X O -40
-KPX X C -39
-KPX Y v -36
-KPX Y u -57
-KPX Y semicolon -93
-KPX Y period -84
-KPX Y p -53
-KPX Y oslash -74
-KPX Y o -76
-KPX Y i -11
-KPX Y hyphen -55
-KPX Y guilsinglleft -101
-KPX Y guillemotleft -105
-KPX Y g -73
-KPX Y e -66
-KPX Y comma -85
-KPX Y colon -90
-KPX Y ae -71
-KPX Y a -71
-KPX Y T 14
-KPX Y S -39
-KPX Y Otilde -61
-KPX Y Oslash -58
-KPX Y Ograve -61
-KPX Y Odieresis -61
-KPX Y Ocircumflex -61
-KPX Y Oacute -61
-KPX Y O -61
-KPX Y G -61
-KPX Y C -60
-KPX Y Atilde -91
-KPX Y Aring -91
-KPX Y Agrave -91
-KPX Y Adieresis -91
-KPX Y Acircumflex -91
-KPX Y Aacute -91
-KPX Y AE -81
-KPX Y A -91
-KPX Z y -19
-KPX Z v -21
-KPX quoteleft Y -20
-KPX quoteleft W 5
-KPX quoteleft V -4
-KPX quoteleft T -15
-KPX quoteleft Aring -76
-KPX quoteleft Adieresis -76
-KPX quoteleft Aacute -76
-KPX quoteleft AE -69
-KPX quoteleft A -76
-KPX a y -24
-KPX a w -10
-KPX a v -23
-KPX a quoteright -14
-KPX a j -7
-KPX b y -25
-KPX b w -9
-KPX b v -23
-KPX c k -5
-KPX c h -9
-KPX e y -25
-KPX e x -25
-KPX e w -9
-KPX e v -22
-KPX e t -9
-KPX e quoteright -13
-KPX f t 14
-KPX f s -10
-KPX f oslash -16
-KPX f oe -11
-KPX f odieresis -16
-KPX f oacute -16
-KPX f o -16
-KPX f l -13
-KPX f j -15
-KPX f i -13
-KPX f f 14
-KPX f eacute -6
-KPX f e -6
-KPX f aring -6
-KPX f ae -6
-KPX f adieresis -6
-KPX f aacute -6
-KPX f a -6
-KPX g r -3
-KPX g odieresis -8
-KPX g oacute -8
-KPX g l -5
-KPX g eacute 1
-KPX g e 1
-KPX g aring -3
-KPX g ae -4
-KPX g adieresis -3
-KPX g a -3
-KPX h y -25
-KPX h quoteright -15
-KPX i j -7
-KPX i T -12
-KPX k udieresis -8
-KPX k u -8
-KPX k s -23
-KPX k period -3
-KPX k odieresis -28
-KPX k oacute -28
-KPX k o -28
-KPX k hyphen -31
-KPX k g -26
-KPX k eacute -19
-KPX k e -19
-KPX k comma -3
-KPX k aring -13
-KPX k ae -15
-KPX k adieresis -13
-KPX k aacute -13
-KPX k a -13
-KPX l y -11
-KPX l v -14
-KPX m y -23
-KPX m w -9
-KPX m v -23
-KPX m p -1
-KPX n y -25
-KPX n w -11
-KPX n v -24
-KPX n quoteright -15
-KPX n p -2
-KPX n T -87
-KPX o y -29
-KPX o x -30
-KPX o w -13
-KPX o v -27
-KPX o t -13
-KPX o quoteright -19
-KPX o T -90
-KPX p y -25
-KPX p t -10
-KPX q u -3
-KPX q c -3
-KPX r z 2
-KPX r y 14
-KPX r x 7
-KPX r w 17
-KPX r v 12
-KPX r u -8
-KPX r t 15
-KPX r semicolon -37
-KPX r s -4
-KPX r r -10
-KPX r quoteright 4
-KPX r q -2
-KPX r period -63
-KPX r p -7
-KPX r oslash -12
-KPX r ograve -7
-KPX r oe -2
-KPX r odieresis -7
-KPX r ocircumflex -7
-KPX r oacute -7
-KPX r o -7
-KPX r n -10
-KPX r m -8
-KPX r l -12
-KPX r k -8
-KPX r j -13
-KPX r i -12
-KPX r hyphen -40
-KPX r h -12
-KPX r g -7
-KPX r f 15
-KPX r egrave 2
-KPX r ecircumflex 2
-KPX r eacute 2
-KPX r e 2
-KPX r d -5
-KPX r comma -64
-KPX r colon -36
-KPX r ccedilla -6
-KPX r c -6
-KPX r aring -1
-KPX r agrave -1
-KPX r ae -2
-KPX r adieresis -1
-KPX r acircumflex -1
-KPX r aacute -1
-KPX r a -1
-KPX s t -9
-KPX s quoteright -12
-KPX t semicolon -42
-KPX t quoteright -3
-KPX t odieresis -15
-KPX t oacute -15
-KPX t o -15
-KPX t h -9
-KPX t eacute -5
-KPX t e -5
-KPX t colon -41
-KPX t aring -3
-KPX t ae -5
-KPX t adieresis -3
-KPX t aacute -3
-KPX t a -3
-KPX t S -9
-KPX u quoteright -8
-KPX v semicolon -43
-KPX v s -25
-KPX v period -55
-KPX v oslash -28
-KPX v ograve -28
-KPX v odieresis -28
-KPX v oacute -28
-KPX v o -28
-KPX v l -12
-KPX v hyphen -5
-KPX v g -26
-KPX v egrave -18
-KPX v ecircumflex -18
-KPX v eacute -18
-KPX v e -18
-KPX v comma -57
-KPX v colon -41
-KPX v c -25
-KPX v atilde -21
-KPX v aring -21
-KPX v agrave -21
-KPX v ae -21
-KPX v adieresis -21
-KPX v acircumflex -21
-KPX v aacute -21
-KPX v a -21
-KPX w semicolon -38
-KPX w s -15
-KPX w period -36
-KPX w oslash -14
-KPX w ograve -15
-KPX w odieresis -15
-KPX w oacute -15
-KPX w o -15
-KPX w l -8
-KPX w hyphen 7
-KPX w g -13
-KPX w egrave -5
-KPX w ecircumflex -5
-KPX w eacute -5
-KPX w e -5
-KPX w comma -38
-KPX w colon -36
-KPX w c -12
-KPX w atilde -11
-KPX w aring -11
-KPX w agrave -11
-KPX w ae -12
-KPX w adieresis -11
-KPX w acircumflex -11
-KPX w aacute -11
-KPX w a -11
-KPX x q -23
-KPX x o -30
-KPX x eacute -20
-KPX x e -20
-KPX x c -27
-KPX x a -22
-KPX y semicolon -43
-KPX y s -24
-KPX y period -55
-KPX y oslash -27
-KPX y ograve -28
-KPX y odieresis -28
-KPX y oacute -28
-KPX y o -28
-KPX y l -11
-KPX y hyphen -4
-KPX y g -27
-KPX y egrave -19
-KPX y ecircumflex -19
-KPX y eacute -19
-KPX y e -19
-KPX y comma -58
-KPX y colon -40
-KPX y c -26
-KPX y atilde -20
-KPX y aring -20
-KPX y agrave -20
-KPX y ae -20
-KPX y adieresis -20
-KPX y acircumflex -20
-KPX y aacute -20
-KPX y a -20
-KPX quotedblleft Y -15
-KPX quotedblleft W 9
-KPX quotedblleft T -11
-KPX quotedblleft Aring -72
-KPX quotedblleft Adieresis -72
-KPX quotedblleft Aacute -72
-KPX quotedblleft AE -64
-KPX quotedblleft A -72
-KPX guilsinglright Y -113
-KPX guilsinglright W -60
-KPX guilsinglright V -79
-KPX guilsinglright T -110
-KPX guilsinglright Aring -52
-KPX guilsinglright Adieresis -52
-KPX guilsinglright Aacute -52
-KPX guilsinglright AE -42
-KPX guilsinglright A -52
-KPX quotedblbase Y -96
-KPX quotedblbase W -54
-KPX quotedblbase V -77
-KPX quotedblbase T -79
-KPX quotedblbase AE 19
-KPX quotedblbase A 7
-KPX quotedblright Y -14
-KPX quotedblright W 11
-KPX quotedblright V 1
-KPX quotedblright T -7
-KPX quotedblright Aring -72
-KPX quotedblright Adieresis -72
-KPX quotedblright Aacute -72
-KPX quotedblright AE -64
-KPX quotedblright A -72
-KPX guillemotright Y -117
-KPX guillemotright W -65
-KPX guillemotright V -84
-KPX guillemotright T -115
-KPX guillemotright Aring -56
-KPX guillemotright Adieresis -56
-KPX guillemotright Aacute -56
-KPX guillemotright AE -46
-KPX guillemotright A -56
-KPX Oslash A -34
-KPX ae y -23
-KPX ae w -7
-KPX ae v -21
-KPX Adieresis y -41
-KPX Adieresis w -28
-KPX Adieresis v -42
-KPX Adieresis u -17
-KPX Adieresis t -22
-KPX Adieresis quoteright -67
-KPX Adieresis quotedblright -71
-KPX Adieresis q -13
-KPX Adieresis period 12
-KPX Adieresis o -20
-KPX Adieresis hyphen 2
-KPX Adieresis guilsinglleft -44
-KPX Adieresis guillemotleft -48
-KPX Adieresis g -20
-KPX Adieresis d -17
-KPX Adieresis comma 9
-KPX Adieresis c -17
-KPX Adieresis b -10
-KPX Adieresis a -11
-KPX Adieresis Y -96
-KPX Adieresis W -57
-KPX Adieresis V -74
-KPX Adieresis U -38
-KPX Adieresis T -91
-KPX Adieresis Q -39
-KPX Adieresis O -38
-KPX Adieresis G -38
-KPX Adieresis C -37
-KPX Aacute y -41
-KPX Aacute w -29
-KPX Aacute v -42
-KPX Aacute u -18
-KPX Aacute t -22
-KPX Aacute quoteright -67
-KPX Aacute q -14
-KPX Aacute period 12
-KPX Aacute o -20
-KPX Aacute hyphen 2
-KPX Aacute guilsinglleft -45
-KPX Aacute guillemotleft -48
-KPX Aacute g -20
-KPX Aacute e -11
-KPX Aacute d -17
-KPX Aacute comma 9
-KPX Aacute c -17
-KPX Aacute b -10
-KPX Aacute a -11
-KPX Aacute Y -96
-KPX Aacute W -57
-KPX Aacute V -74
-KPX Aacute U -38
-KPX Aacute T -91
-KPX Aacute Q -40
-KPX Aacute O -38
-KPX Aacute G -38
-KPX Aacute C -37
-KPX Agrave period 13
-KPX Agrave comma 9
-KPX Agrave Y -96
-KPX Agrave W -57
-KPX Agrave V -74
-KPX Agrave U -37
-KPX Agrave T -91
-KPX Agrave Q -39
-KPX Agrave O -37
-KPX Agrave G -38
-KPX Agrave C -36
-KPX Acircumflex period 13
-KPX Acircumflex comma 9
-KPX Acircumflex Y -96
-KPX Acircumflex W -57
-KPX Acircumflex V -74
-KPX Acircumflex U -37
-KPX Acircumflex T -91
-KPX Acircumflex Q -39
-KPX Acircumflex O -37
-KPX Acircumflex G -38
-KPX Acircumflex C -36
-KPX Atilde period 11
-KPX Atilde comma 9
-KPX Atilde Y -96
-KPX Atilde W -57
-KPX Atilde V -74
-KPX Atilde U -39
-KPX Atilde T -92
-KPX Atilde Q -41
-KPX Atilde O -39
-KPX Atilde G -40
-KPX Atilde C -38
-KPX Aring y -41
-KPX Aring w -28
-KPX Aring v -42
-KPX Aring u -17
-KPX Aring t -21
-KPX Aring quoteright -67
-KPX Aring quotedblright -71
-KPX Aring q -13
-KPX Aring period 13
-KPX Aring o -19
-KPX Aring hyphen 2
-KPX Aring guilsinglleft -44
-KPX Aring guillemotleft -48
-KPX Aring g -20
-KPX Aring e -10
-KPX Aring d -17
-KPX Aring comma 9
-KPX Aring c -17
-KPX Aring b -10
-KPX Aring a -11
-KPX Aring Y -96
-KPX Aring W -57
-KPX Aring V -74
-KPX Aring U -37
-KPX Aring T -91
-KPX Aring Q -39
-KPX Aring O -37
-KPX Aring G -38
-KPX Aring C -36
-KPX Ccedilla A -34
-KPX Odieresis Y -65
-KPX Odieresis X -43
-KPX Odieresis W -24
-KPX Odieresis V -40
-KPX Odieresis T -32
-KPX Odieresis A -42
-KPX Oacute Y -65
-KPX Oacute W -24
-KPX Oacute V -40
-KPX Oacute T -32
-KPX Oacute A -42
-KPX Ograve Y -65
-KPX Ograve V -40
-KPX Ograve T -32
-KPX Ocircumflex Y -65
-KPX Ocircumflex V -40
-KPX Ocircumflex T -32
-KPX Otilde Y -65
-KPX Otilde V -40
-KPX Otilde T -32
-KPX Udieresis r -5
-KPX Udieresis period -12
-KPX Udieresis p -3
-KPX Udieresis n -5
-KPX Udieresis m -3
-KPX Udieresis comma -17
-KPX Udieresis b -4
-KPX Udieresis A -40
-KPX Uacute r -5
-KPX Uacute period -12
-KPX Uacute p -3
-KPX Uacute n -5
-KPX Uacute m -3
-KPX Uacute comma -17
-KPX Uacute A -40
-KPX Ugrave A -40
-KPX Ucircumflex A -40
-KPX adieresis y -24
-KPX adieresis w -10
-KPX adieresis v -23
-KPX aacute y -24
-KPX aacute w -10
-KPX aacute v -23
-KPX agrave y -24
-KPX agrave w -10
-KPX agrave v -23
-KPX aring y -24
-KPX aring w -10
-KPX aring v -23
-KPX eacute y -25
-KPX eacute w -9
-KPX eacute v -22
-KPX ecircumflex y -25
-KPX ecircumflex w -9
-KPX ecircumflex v -22
-KPX odieresis y -29
-KPX odieresis x -30
-KPX odieresis w -13
-KPX odieresis v -27
-KPX odieresis t -13
-KPX oacute y -29
-KPX oacute w -13
-KPX oacute v -27
-KPX ograve y -29
-KPX ograve w -13
-KPX ograve v -27
-KPX ocircumflex t -13
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-sans-l/n019024l.pfb b/src/fonts/nimbus-sans-l/n019024l.pfb
deleted file mode 100644
index e95c48c..0000000
--- a/src/fonts/nimbus-sans-l/n019024l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019024l.pfm b/src/fonts/nimbus-sans-l/n019024l.pfm
deleted file mode 100644
index 4775556..0000000
--- a/src/fonts/nimbus-sans-l/n019024l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019043l.afm b/src/fonts/nimbus-sans-l/n019043l.afm
deleted file mode 100644
index ab7884d..0000000
--- a/src/fonts/nimbus-sans-l/n019043l.afm
+++ /dev/null
@@ -1,1566 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 14:44:47 2007
-FontName NimbusSanL-ReguCond
-FullName Nimbus Sans L Regular Condensed
-FamilyName Nimbus Sans L
-Weight Regular
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle 0
-IsFixedPitch false
-UnderlinePosition -100
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -136 -282 893 959
-CapHeight 718
-XHeight 523
-Ascender 718
-Descender -207
-StartCharMetrics 562
-C 32 ; WX 228 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 228 ; N exclam ; B 74 0 153 718 ;
-C 34 ; WX 291 ; N quotedbl ; B 57 463 234 718 ;
-C 35 ; WX 456 ; N numbersign ; B 23 0 434 688 ;
-C 36 ; WX 456 ; N dollar ; B 26 -115 427 775 ;
-C 37 ; WX 729 ; N percent ; B 32 -19 697 703 ;
-C 38 ; WX 547 ; N ampersand ; B 36 -15 529 718 ;
-C 39 ; WX 182 ; N quoteright ; B 43 462 129 718 ;
-C 40 ; WX 273 ; N parenleft ; B 56 -207 245 733 ;
-C 41 ; WX 273 ; N parenright ; B 28 -207 217 733 ;
-C 42 ; WX 319 ; N asterisk ; B 32 431 286 718 ;
-C 43 ; WX 479 ; N plus ; B 32 0 447 505 ;
-C 44 ; WX 228 ; N comma ; B 71 -147 157 107 ;
-C 45 ; WX 273 ; N hyphen ; B 36 232 237 322 ;
-C 46 ; WX 228 ; N period ; B 71 0 157 107 ;
-C 47 ; WX 228 ; N slash ; B -14 -19 242 737 ;
-C 48 ; WX 456 ; N zero ; B 30 -19 426 703 ;
-C 49 ; WX 456 ; N one ; B 83 0 294 703 ;
-C 50 ; WX 456 ; N two ; B 21 0 416 703 ;
-C 51 ; WX 456 ; N three ; B 28 -19 428 703 ;
-C 52 ; WX 456 ; N four ; B 20 0 429 703 ;
-C 53 ; WX 456 ; N five ; B 26 -19 421 688 ;
-C 54 ; WX 456 ; N six ; B 31 -19 425 703 ;
-C 55 ; WX 456 ; N seven ; B 30 0 429 688 ;
-C 56 ; WX 456 ; N eight ; B 31 -19 424 703 ;
-C 57 ; WX 456 ; N nine ; B 34 -19 421 703 ;
-C 58 ; WX 228 ; N colon ; B 71 0 157 516 ;
-C 59 ; WX 228 ; N semicolon ; B 71 -147 157 516 ;
-C 60 ; WX 479 ; N less ; B 39 10 440 496 ;
-C 61 ; WX 479 ; N equal ; B 32 115 447 390 ;
-C 62 ; WX 479 ; N greater ; B 39 10 440 496 ;
-C 63 ; WX 456 ; N question ; B 46 0 403 727 ;
-C 64 ; WX 832 ; N at ; B 121 -19 712 737 ;
-C 65 ; WX 547 ; N A ; B 11 0 536 718 ;
-C 66 ; WX 547 ; N B ; B 61 0 514 718 ;
-C 67 ; WX 592 ; N C ; B 36 -19 558 737 ;
-C 68 ; WX 592 ; N D ; B 66 0 553 718 ;
-C 69 ; WX 547 ; N E ; B 71 0 505 718 ;
-C 70 ; WX 501 ; N F ; B 71 0 478 718 ;
-C 71 ; WX 638 ; N G ; B 39 -19 577 737 ;
-C 72 ; WX 592 ; N H ; B 63 0 530 718 ;
-C 73 ; WX 228 ; N I ; B 75 0 154 718 ; L J IJ ;
-C 74 ; WX 410 ; N J ; B 14 -19 351 718 ;
-C 75 ; WX 547 ; N K ; B 62 0 544 718 ;
-C 76 ; WX 456 ; N L ; B 62 0 440 718 ; L periodcentered Ldot ;
-C 77 ; WX 683 ; N M ; B 60 0 624 718 ;
-C 78 ; WX 592 ; N N ; B 62 0 530 718 ; L o afii61352 ;
-C 79 ; WX 638 ; N O ; B 32 -19 606 737 ;
-C 80 ; WX 547 ; N P ; B 71 0 510 718 ;
-C 81 ; WX 638 ; N Q ; B 32 -56 606 737 ;
-C 82 ; WX 592 ; N R ; B 72 0 561 718 ;
-C 83 ; WX 547 ; N S ; B 40 -19 508 737 ;
-C 84 ; WX 501 ; N T ; B 11 0 490 718 ; L M trademark ;
-C 85 ; WX 592 ; N U ; B 65 -19 528 718 ;
-C 86 ; WX 547 ; N V ; B 16 0 531 718 ;
-C 87 ; WX 774 ; N W ; B 13 0 761 718 ;
-C 88 ; WX 547 ; N X ; B 16 0 531 718 ;
-C 89 ; WX 547 ; N Y ; B 11 0 535 718 ;
-C 90 ; WX 501 ; N Z ; B 19 0 482 718 ;
-C 91 ; WX 228 ; N bracketleft ; B 52 -196 205 722 ;
-C 92 ; WX 228 ; N backslash ; B -14 -19 242 737 ;
-C 93 ; WX 228 ; N bracketright ; B 23 -196 176 722 ;
-C 94 ; WX 385 ; N asciicircum ; B -11 264 396 688 ;
-C 95 ; WX 456 ; N underscore ; B 0 -125 456 -75 ;
-C 96 ; WX 182 ; N quoteleft ; B 53 469 139 725 ;
-C 97 ; WX 456 ; N a ; B 30 -15 435 538 ;
-C 98 ; WX 456 ; N b ; B 48 -15 424 718 ;
-C 99 ; WX 410 ; N c ; B 25 -15 391 538 ;
-C 100 ; WX 456 ; N d ; B 29 -15 409 718 ;
-C 101 ; WX 456 ; N e ; B 33 -15 423 538 ;
-C 102 ; WX 228 ; N f ; B 11 0 215 728 ; L l fl ; L i fi ;
-C 103 ; WX 456 ; N g ; B 33 -220 409 538 ;
-C 104 ; WX 456 ; N h ; B 53 0 403 718 ;
-C 105 ; WX 182 ; N i ; B 55 0 127 718 ; L j ij ;
-C 106 ; WX 182 ; N j ; B -13 -210 127 718 ;
-C 107 ; WX 410 ; N k ; B 55 0 411 718 ;
-C 108 ; WX 182 ; N l ; B 55 0 127 718 ; L periodcentered ldot ;
-C 109 ; WX 683 ; N m ; B 53 0 631 538 ;
-C 110 ; WX 456 ; N n ; B 53 0 403 538 ;
-C 111 ; WX 456 ; N o ; B 29 -14 427 538 ;
-C 112 ; WX 456 ; N p ; B 48 -207 424 538 ;
-C 113 ; WX 456 ; N q ; B 29 -207 405 538 ;
-C 114 ; WX 273 ; N r ; B 63 0 272 538 ;
-C 115 ; WX 410 ; N s ; B 26 -15 380 538 ;
-C 116 ; WX 228 ; N t ; B 11 -7 211 669 ;
-C 117 ; WX 456 ; N u ; B 56 -15 401 523 ;
-C 118 ; WX 410 ; N v ; B 7 0 403 523 ;
-C 119 ; WX 592 ; N w ; B 11 0 581 523 ;
-C 120 ; WX 410 ; N x ; B 9 0 402 523 ;
-C 121 ; WX 410 ; N y ; B 9 -214 401 523 ;
-C 122 ; WX 410 ; N z ; B 25 0 385 523 ;
-C 123 ; WX 274 ; N braceleft ; B 34 -196 239 722 ;
-C 124 ; WX 213 ; N bar ; B 77 -19 137 737 ;
-C 125 ; WX 274 ; N braceright ; B 34 -196 239 722 ;
-C 126 ; WX 479 ; N asciitilde ; B 50 181 429 322 ;
-C 161 ; WX 273 ; N exclamdown ; B 97 -195 176 523 ;
-C 162 ; WX 456 ; N cent ; B 42 -115 421 623 ;
-C 163 ; WX 456 ; N sterling ; B 27 -16 442 718 ;
-C 164 ; WX 137 ; N fraction ; B -136 -19 273 703 ;
-C 165 ; WX 456 ; N yen ; B 2 0 453 688 ;
-C 166 ; WX 456 ; N florin ; B -9 -207 411 737 ;
-C 167 ; WX 456 ; N section ; B 35 -191 420 737 ;
-C 168 ; WX 456 ; N currency ; B 23 99 433 603 ;
-C 169 ; WX 157 ; N quotesingle ; B 48 463 108 718 ;
-C 170 ; WX 273 ; N quotedblleft ; B 31 469 252 725 ;
-C 171 ; WX 456 ; N guillemotleft ; B 80 108 376 446 ;
-C 172 ; WX 273 ; N guilsinglleft ; B 72 108 201 446 ;
-C 173 ; WX 273 ; N guilsinglright ; B 72 108 201 446 ;
-C 174 ; WX 410 ; N fi ; B 11 0 356 728 ;
-C 175 ; WX 410 ; N fl ; B 11 0 354 728 ;
-C 177 ; WX 456 ; N endash ; B 0 240 456 313 ;
-C 178 ; WX 456 ; N dagger ; B 35 -159 421 718 ;
-C 179 ; WX 456 ; N daggerdbl ; B 35 -159 421 718 ;
-C 180 ; WX 228 ; N periodcentered ; B 63 190 166 315 ;
-C 182 ; WX 440 ; N paragraph ; B 15 -173 408 718 ;
-C 183 ; WX 287 ; N bullet ; B 15 202 273 517 ;
-C 184 ; WX 182 ; N quotesinglbase ; B 43 -149 129 107 ;
-C 185 ; WX 273 ; N quotedblbase ; B 21 -149 242 107 ;
-C 186 ; WX 273 ; N quotedblright ; B 21 462 242 718 ;
-C 187 ; WX 456 ; N guillemotright ; B 80 108 376 446 ;
-C 188 ; WX 820 ; N ellipsis ; B 94 0 726 107 ;
-C 189 ; WX 820 ; N perthousand ; B 6 -19 815 703 ;
-C 191 ; WX 501 ; N questiondown ; B 75 -201 432 525 ;
-C 193 ; WX 273 ; N grave ; B 11 593 173 734 ;
-C 194 ; WX 273 ; N acute ; B 100 593 262 734 ;
-C 195 ; WX 273 ; N circumflex ; B 17 593 256 734 ;
-C 196 ; WX 273 ; N tilde ; B -3 606 276 722 ;
-C 197 ; WX 273 ; N macron ; B 8 627 265 684 ;
-C 198 ; WX 273 ; N breve ; B 11 595 263 731 ;
-C 199 ; WX 273 ; N dotaccent ; B 99 604 174 706 ;
-C 200 ; WX 273 ; N dieresis ; B 33 604 240 706 ;
-C 202 ; WX 273 ; N ring ; B 61 572 212 756 ;
-C 203 ; WX 273 ; N cedilla ; B 37 -225 212 0 ;
-C 205 ; WX 273 ; N hungarumlaut ; B 25 593 335 734 ;
-C 206 ; WX 273 ; N ogonek ; B 60 -225 235 0 ;
-C 207 ; WX 273 ; N caron ; B 17 593 256 734 ;
-C 208 ; WX 820 ; N emdash ; B 0 240 820 313 ;
-C 225 ; WX 820 ; N AE ; B 7 0 780 718 ;
-C 227 ; WX 303 ; N ordfeminine ; B 20 304 284 737 ;
-C 232 ; WX 456 ; N Lslash ; B -16 0 440 718 ;
-C 233 ; WX 638 ; N Oslash ; B 32 -19 607 737 ;
-C 234 ; WX 820 ; N OE ; B 30 -19 791 737 ;
-C 235 ; WX 299 ; N ordmasculine ; B 20 304 280 737 ;
-C 241 ; WX 729 ; N ae ; B 30 -15 695 538 ;
-C 245 ; WX 228 ; N dotlessi ; B 78 0 150 523 ;
-C 248 ; WX 182 ; N lslash ; B -16 0 198 718 ;
-C 249 ; WX 501 ; N oslash ; B 23 -22 440 545 ;
-C 250 ; WX 774 ; N oe ; B 29 -15 740 538 ;
-C 251 ; WX 501 ; N germandbls ; B 55 -15 468 728 ;
-C -1 ; WX 547 ; N Adieresis ; B 11 0 536 901 ;
-C -1 ; WX 547 ; N Aacute ; B 11 0 536 929 ;
-C -1 ; WX 547 ; N Agrave ; B 11 0 536 929 ;
-C -1 ; WX 547 ; N Acircumflex ; B 11 0 536 929 ;
-C -1 ; WX 547 ; N Abreve ; B 11 0 536 926 ;
-C -1 ; WX 547 ; N Atilde ; B 11 0 536 917 ;
-C -1 ; WX 547 ; N Aring ; B 11 0 536 944 ;
-C -1 ; WX 547 ; N Aogonek ; B 11 -225 567 718 ;
-C -1 ; WX 592 ; N Ccedilla ; B 36 -225 558 737 ;
-C -1 ; WX 592 ; N Cacute ; B 36 -19 558 903 ;
-C -1 ; WX 592 ; N Ccaron ; B 36 -19 558 929 ;
-C -1 ; WX 592 ; N Dcaron ; B 66 0 553 929 ;
-C -1 ; WX 547 ; N Edieresis ; B 71 0 505 901 ;
-C -1 ; WX 547 ; N Eacute ; B 71 0 505 929 ;
-C -1 ; WX 547 ; N Egrave ; B 71 0 505 929 ;
-C -1 ; WX 547 ; N Ecircumflex ; B 71 0 505 929 ;
-C -1 ; WX 547 ; N Ecaron ; B 71 0 505 929 ;
-C -1 ; WX 547 ; N Edotaccent ; B 71 0 505 901 ;
-C -1 ; WX 547 ; N Eogonek ; B 71 -225 536 718 ;
-C -1 ; WX 638 ; N Gbreve ; B 39 -19 577 926 ;
-C -1 ; WX 228 ; N Idieresis ; B 11 0 218 901 ;
-C -1 ; WX 228 ; N Iacute ; B 75 0 240 903 ;
-C -1 ; WX 228 ; N Igrave ; B -11 0 154 929 ;
-C -1 ; WX 228 ; N Icircumflex ; B -5 0 234 929 ;
-C -1 ; WX 228 ; N Idotaccent ; B 75 0 154 901 ;
-C -1 ; WX 456 ; N Lacute ; B 62 0 440 903 ;
-C -1 ; WX 456 ; N Lcaron ; B 62 0 440 718 ;
-C -1 ; WX 592 ; N Nacute ; B 62 0 530 903 ;
-C -1 ; WX 592 ; N Ncaron ; B 62 0 530 929 ;
-C -1 ; WX 592 ; N Ntilde ; B 62 0 530 917 ;
-C -1 ; WX 638 ; N Odieresis ; B 32 -19 606 901 ;
-C -1 ; WX 638 ; N Oacute ; B 32 -19 606 929 ;
-C -1 ; WX 638 ; N Ograve ; B 32 -19 606 929 ;
-C -1 ; WX 638 ; N Ocircumflex ; B 32 -19 606 929 ;
-C -1 ; WX 638 ; N Otilde ; B 32 -19 606 917 ;
-C -1 ; WX 638 ; N Ohungarumlaut ; B 32 -19 606 929 ;
-C -1 ; WX 592 ; N Racute ; B 72 0 561 903 ;
-C -1 ; WX 592 ; N Rcaron ; B 72 0 561 929 ;
-C -1 ; WX 547 ; N Sacute ; B 40 -19 508 903 ;
-C -1 ; WX 547 ; N Scaron ; B 40 -19 508 929 ;
-C -1 ; WX 547 ; N Scedilla ; B 39 -225 508 737 ;
-C -1 ; WX 501 ; N Tcaron ; B 11 0 490 929 ;
-C -1 ; WX 592 ; N Udieresis ; B 65 -19 528 901 ;
-C -1 ; WX 592 ; N Uacute ; B 65 -19 528 929 ;
-C -1 ; WX 592 ; N Ugrave ; B 65 -19 528 929 ;
-C -1 ; WX 592 ; N Ucircumflex ; B 65 -19 528 929 ;
-C -1 ; WX 592 ; N Uring ; B 65 -19 528 951 ;
-C -1 ; WX 592 ; N Uhungarumlaut ; B 65 -19 528 929 ;
-C -1 ; WX 547 ; N Yacute ; B 11 0 535 929 ;
-C -1 ; WX 501 ; N Zacute ; B 19 0 482 903 ;
-C -1 ; WX 501 ; N Zcaron ; B 19 0 482 929 ;
-C -1 ; WX 501 ; N Zdotaccent ; B 19 0 482 901 ;
-C -1 ; WX 547 ; N Amacron ; B 11 0 536 879 ;
-C -1 ; WX 501 ; N Tcommaaccent ; B 11 -282 490 718 ;
-C -1 ; WX 547 ; N Ydieresis ; B 11 0 535 901 ;
-C -1 ; WX 547 ; N Emacron ; B 71 0 505 879 ;
-C -1 ; WX 228 ; N Imacron ; B -15 0 242 879 ;
-C -1 ; WX 228 ; N Iogonek ; B 10 -225 185 718 ;
-C -1 ; WX 547 ; N Kcommaaccent ; B 62 -282 544 718 ;
-C -1 ; WX 456 ; N Lcommaaccent ; B 62 -282 440 718 ;
-C -1 ; WX 592 ; N Ncommaaccent ; B 62 -282 530 718 ;
-C -1 ; WX 638 ; N Omacron ; B 32 -19 606 879 ;
-C -1 ; WX 592 ; N Rcommaaccent ; B 72 -282 561 718 ;
-C -1 ; WX 638 ; N Gcommaaccent ; B 39 -282 577 737 ;
-C -1 ; WX 592 ; N Umacron ; B 65 -19 528 879 ;
-C -1 ; WX 592 ; N Uogonek ; B 65 -225 528 718 ;
-C -1 ; WX 456 ; N adieresis ; B 30 -15 435 706 ;
-C -1 ; WX 456 ; N aacute ; B 30 -15 435 734 ;
-C -1 ; WX 456 ; N agrave ; B 30 -15 435 734 ;
-C -1 ; WX 456 ; N acircumflex ; B 30 -15 435 734 ;
-C -1 ; WX 456 ; N abreve ; B 30 -15 435 731 ;
-C -1 ; WX 456 ; N atilde ; B 30 -15 435 722 ;
-C -1 ; WX 456 ; N aring ; B 30 -15 435 769 ;
-C -1 ; WX 456 ; N aogonek ; B 30 -225 466 538 ;
-C -1 ; WX 410 ; N cacute ; B 25 -15 391 734 ;
-C -1 ; WX 410 ; N ccaron ; B 25 -15 391 734 ;
-C -1 ; WX 410 ; N ccedilla ; B 25 -225 391 538 ;
-C -1 ; WX 496 ; N dcaron ; B 29 -15 516 718 ;
-C -1 ; WX 456 ; N edieresis ; B 33 -15 423 706 ;
-C -1 ; WX 456 ; N eacute ; B 33 -15 423 734 ;
-C -1 ; WX 456 ; N egrave ; B 33 -15 423 734 ;
-C -1 ; WX 456 ; N ecircumflex ; B 33 -15 423 734 ;
-C -1 ; WX 456 ; N ecaron ; B 33 -15 423 734 ;
-C -1 ; WX 456 ; N edotaccent ; B 33 -15 423 706 ;
-C -1 ; WX 456 ; N eogonek ; B 33 -225 423 538 ;
-C -1 ; WX 456 ; N gbreve ; B 33 -220 409 731 ;
-C -1 ; WX 228 ; N idieresis ; B 11 0 218 706 ;
-C -1 ; WX 228 ; N iacute ; B 78 0 240 734 ;
-C -1 ; WX 228 ; N igrave ; B -11 0 151 734 ;
-C -1 ; WX 228 ; N icircumflex ; B -5 0 234 734 ;
-C -1 ; WX 182 ; N lacute ; B 55 0 217 903 ;
-C -1 ; WX 212 ; N lcaron ; B 55 0 232 718 ;
-C -1 ; WX 456 ; N nacute ; B 53 0 403 734 ;
-C -1 ; WX 456 ; N ncaron ; B 53 0 403 734 ;
-C -1 ; WX 456 ; N ntilde ; B 53 0 403 722 ;
-C -1 ; WX 456 ; N odieresis ; B 29 -14 427 706 ;
-C -1 ; WX 456 ; N oacute ; B 29 -14 427 734 ;
-C -1 ; WX 456 ; N ograve ; B 29 -14 427 734 ;
-C -1 ; WX 456 ; N ocircumflex ; B 29 -14 427 734 ;
-C -1 ; WX 456 ; N otilde ; B 29 -14 427 722 ;
-C -1 ; WX 456 ; N ohungarumlaut ; B 29 -14 427 734 ;
-C -1 ; WX 273 ; N racute ; B 63 0 272 734 ;
-C -1 ; WX 410 ; N sacute ; B 26 -15 380 734 ;
-C -1 ; WX 410 ; N scaron ; B 26 -15 380 734 ;
-C -1 ; WX 410 ; N scommaaccent ; B 26 -282 380 538 ;
-C -1 ; WX 248 ; N tcaron ; B 11 -7 268 718 ;
-C -1 ; WX 456 ; N udieresis ; B 56 -15 401 706 ;
-C -1 ; WX 456 ; N uacute ; B 56 -15 401 734 ;
-C -1 ; WX 456 ; N ugrave ; B 56 -15 401 734 ;
-C -1 ; WX 456 ; N ucircumflex ; B 56 -15 401 734 ;
-C -1 ; WX 456 ; N uring ; B 56 -15 401 756 ;
-C -1 ; WX 456 ; N uhungarumlaut ; B 56 -15 427 734 ;
-C -1 ; WX 410 ; N yacute ; B 9 -214 401 734 ;
-C -1 ; WX 410 ; N zacute ; B 25 0 385 734 ;
-C -1 ; WX 410 ; N zcaron ; B 25 0 385 734 ;
-C -1 ; WX 410 ; N zdotaccent ; B 25 0 385 706 ;
-C -1 ; WX 410 ; N ydieresis ; B 9 -214 401 706 ;
-C -1 ; WX 228 ; N tcommaaccent ; B 11 -282 211 669 ;
-C -1 ; WX 456 ; N amacron ; B 30 -15 435 684 ;
-C -1 ; WX 456 ; N emacron ; B 33 -15 423 684 ;
-C -1 ; WX 228 ; N imacron ; B -15 0 242 684 ;
-C -1 ; WX 410 ; N kcommaaccent ; B 55 -282 411 718 ;
-C -1 ; WX 182 ; N lcommaaccent ; B 50 -282 133 718 ;
-C -1 ; WX 456 ; N ncommaaccent ; B 53 -282 403 538 ;
-C -1 ; WX 456 ; N omacron ; B 29 -14 427 684 ;
-C -1 ; WX 273 ; N rcommaaccent ; B 57 -282 272 538 ;
-C -1 ; WX 456 ; N umacron ; B 56 -15 401 684 ;
-C -1 ; WX 456 ; N uogonek ; B 56 -225 432 523 ;
-C -1 ; WX 273 ; N rcaron ; B 44 0 283 734 ;
-C -1 ; WX 410 ; N scedilla ; B 26 -225 380 538 ;
-C -1 ; WX 456 ; N gcommaaccent ; B 33 -220 409 813 ;
-C -1 ; WX 182 ; N iogonek ; B -17 -225 158 718 ;
-C -1 ; WX 547 ; N Scommaaccent ; B 40 -282 508 737 ;
-C -1 ; WX 592 ; N Eth ; B 0 0 553 718 ;
-C -1 ; WX 592 ; N Dcroat ; B 0 0 553 718 ;
-C -1 ; WX 547 ; N Thorn ; B 71 0 510 718 ;
-C -1 ; WX 456 ; N dcroat ; B 29 -15 456 718 ;
-C -1 ; WX 456 ; N eth ; B 29 -15 428 737 ;
-C -1 ; WX 456 ; N thorn ; B 48 -207 424 718 ;
-C -1 ; WX 510 ; N Euro ; B 0 -12 495 730 ;
-C -1 ; WX 273 ; N onesuperior ; B 35 281 182 703 ;
-C -1 ; WX 273 ; N twosuperior ; B 3 280 265 714 ;
-C -1 ; WX 273 ; N threesuperior ; B 4 270 266 714 ;
-C -1 ; WX 328 ; N degree ; B 44 411 284 703 ;
-C -1 ; WX 479 ; N minus ; B 32 216 447 289 ;
-C -1 ; WX 479 ; N multiply ; B 32 0 447 506 ;
-C -1 ; WX 479 ; N divide ; B 32 -19 447 524 ;
-C -1 ; WX 820 ; N trademark ; B 38 306 740 718 ;
-C -1 ; WX 479 ; N plusminus ; B 32 0 447 561 ;
-C -1 ; WX 684 ; N onehalf ; B 35 -19 634 703 ;
-C -1 ; WX 684 ; N onequarter ; B 60 -19 620 703 ;
-C -1 ; WX 684 ; N threequarters ; B 37 -19 664 714 ;
-C -1 ; WX 273 ; N commaaccent ; B 95 -282 178 -60 ;
-C -1 ; WX 604 ; N copyright ; B -11 -19 617 737 ;
-C -1 ; WX 604 ; N registered ; B -11 -19 617 737 ;
-C -1 ; WX 405 ; N lozenge ; B 15 0 382 740 ;
-C -1 ; WX 502 ; N Delta ; B 5 0 499 688 ;
-C -1 ; WX 479 ; N notequal ; B 32 10 447 495 ;
-C -1 ; WX 450 ; N radical ; B -5 -74 433 927 ;
-C -1 ; WX 479 ; N lessequal ; B 39 0 439 594 ;
-C -1 ; WX 479 ; N greaterequal ; B 39 0 439 594 ;
-C -1 ; WX 479 ; N logicalnot ; B 32 108 447 390 ;
-C -1 ; WX 585 ; N summation ; B 12 -123 570 752 ;
-C -1 ; WX 405 ; N partialdiff ; B 21 -10 379 753 ;
-C -1 ; WX 213 ; N brokenbar ; B 77 -19 137 737 ;
-C -1 ; WX 456 ; N mu ; B 56 -207 401 523 ;
-C -1 ; WX 547 ; N afii10017 ; B 11 0 536 718 ;
-C -1 ; WX 551 ; N afii10018 ; B 61 0 514 718 ;
-C -1 ; WX 547 ; N afii10019 ; B 61 0 514 718 ;
-C -1 ; WX 489 ; N afii10020 ; B 61 0 468 718 ;
-C -1 ; WX 666 ; N afii10021 ; B 21 -120 645 718 ;
-C -1 ; WX 537 ; N afii10022 ; B 61 0 495 718 ;
-C -1 ; WX 537 ; N afii10023 ; B 61 0 495 901 ;
-C -1 ; WX 902 ; N afii10024 ; B 9 0 893 718 ;
-C -1 ; WX 541 ; N afii10025 ; B 42 -19 510 737 ;
-C -1 ; WX 596 ; N afii10026 ; B 61 0 529 718 ;
-C -1 ; WX 596 ; N afii10027 ; B 61 0 529 878 ;
-C -1 ; WX 552 ; N afii10028 ; B 61 0 543 718 ;
-C -1 ; WX 581 ; N afii10029 ; B 21 0 514 718 ;
-C -1 ; WX 692 ; N afii10030 ; B 61 0 625 718 ;
-C -1 ; WX 595 ; N afii10031 ; B 61 0 528 718 ;
-C -1 ; WX 638 ; N afii10032 ; B 32 -19 606 737 ;
-C -1 ; WX 595 ; N afii10033 ; B 61 0 528 718 ;
-C -1 ; WX 547 ; N afii10034 ; B 61 0 500 718 ;
-C -1 ; WX 588 ; N afii10035 ; B 32 -19 554 737 ;
-C -1 ; WX 503 ; N afii10036 ; B 12 0 491 718 ;
-C -1 ; WX 548 ; N afii10037 ; B 12 0 536 718 ;
-C -1 ; WX 737 ; N afii10038 ; B 34 0 703 718 ;
-C -1 ; WX 539 ; N afii10039 ; B 12 0 527 718 ;
-C -1 ; WX 645 ; N afii10040 ; B 61 -120 624 718 ;
-C -1 ; WX 547 ; N afii10041 ; B 62 0 480 718 ;
-C -1 ; WX 698 ; N afii10042 ; B 61 0 631 718 ;
-C -1 ; WX 748 ; N afii10043 ; B 61 -120 727 718 ;
-C -1 ; WX 711 ; N afii10044 ; B 12 0 674 718 ;
-C -1 ; WX 783 ; N afii10045 ; B 61 0 716 718 ;
-C -1 ; WX 537 ; N afii10046 ; B 61 0 500 718 ;
-C -1 ; WX 590 ; N afii10047 ; B 32 -19 554 737 ;
-C -1 ; WX 913 ; N afii10048 ; B 61 -19 881 737 ;
-C -1 ; WX 554 ; N afii10049 ; B 42 0 487 718 ;
-C -1 ; WX 456 ; N afii10065 ; B 30 -15 435 538 ;
-C -1 ; WX 442 ; N afii10066 ; B 25 -14 424 776 ;
-C -1 ; WX 444 ; N afii10067 ; B 54 0 420 523 ;
-C -1 ; WX 337 ; N afii10068 ; B 51 0 325 523 ;
-C -1 ; WX 536 ; N afii10069 ; B 21 -125 515 523 ;
-C -1 ; WX 456 ; N afii10070 ; B 33 -15 423 538 ;
-C -1 ; WX 456 ; N afii10071 ; B 33 -15 423 706 ;
-C -1 ; WX 658 ; N afii10072 ; B 8 0 650 523 ;
-C -1 ; WX 410 ; N afii10073 ; B 24 -15 378 538 ;
-C -1 ; WX 455 ; N afii10074 ; B 53 0 403 523 ;
-C -1 ; WX 455 ; N afii10075 ; B 53 0 403 741 ;
-C -1 ; WX 417 ; N afii10076 ; B 53 0 409 523 ;
-C -1 ; WX 439 ; N afii10077 ; B 21 0 387 523 ;
-C -1 ; WX 539 ; N afii10078 ; B 53 0 487 523 ;
-C -1 ; WX 455 ; N afii10079 ; B 53 0 403 523 ;
-C -1 ; WX 456 ; N afii10080 ; B 29 -14 427 538 ;
-C -1 ; WX 455 ; N afii10081 ; B 53 0 403 523 ;
-C -1 ; WX 456 ; N afii10082 ; B 48 -207 424 538 ;
-C -1 ; WX 410 ; N afii10083 ; B 25 -15 391 538 ;
-C -1 ; WX 336 ; N afii10084 ; B 12 0 324 523 ;
-C -1 ; WX 409 ; N afii10085 ; B 8 -214 400 523 ;
-C -1 ; WX 748 ; N afii10086 ; B 32 -207 716 628 ;
-C -1 ; WX 410 ; N afii10087 ; B 8 0 401 523 ;
-C -1 ; WX 501 ; N afii10088 ; B 53 -125 480 523 ;
-C -1 ; WX 406 ; N afii10089 ; B 53 0 371 523 ;
-C -1 ; WX 589 ; N afii10090 ; B 53 0 537 523 ;
-C -1 ; WX 635 ; N afii10091 ; B 53 -125 614 523 ;
-C -1 ; WX 512 ; N afii10092 ; B 17 0 497 523 ;
-C -1 ; WX 585 ; N afii10093 ; B 53 0 533 523 ;
-C -1 ; WX 444 ; N afii10094 ; B 53 0 419 523 ;
-C -1 ; WX 410 ; N afii10095 ; B 25 -15 391 538 ;
-C -1 ; WX 667 ; N afii10096 ; B 53 -14 638 538 ;
-C -1 ; WX 447 ; N afii10097 ; B 24 0 410 523 ;
-C -1 ; WX 537 ; N uni0400 ; B 61 0 495 959 ;
-C -1 ; WX 631 ; N afii10051 ; B 12 -131 589 718 ;
-C -1 ; WX 489 ; N afii10052 ; B 61 0 468 919 ;
-C -1 ; WX 588 ; N afii10053 ; B 32 -19 554 737 ;
-C -1 ; WX 547 ; N afii10054 ; B 40 -19 508 737 ;
-C -1 ; WX 213 ; N afii10055 ; B 67 0 146 718 ;
-C -1 ; WX 341 ; N afii10056 ; B 67 0 274 901 ;
-C -1 ; WX 410 ; N afii10057 ; B 14 -19 351 718 ;
-C -1 ; WX 896 ; N afii10058 ; B 21 0 873 718 ;
-C -1 ; WX 924 ; N afii10059 ; B 61 0 887 718 ;
-C -1 ; WX 631 ; N afii10060 ; B 12 0 589 718 ;
-C -1 ; WX 552 ; N afii10061 ; B 61 0 543 898 ;
-C -1 ; WX 596 ; N uni040D ; B 61 0 529 959 ;
-C -1 ; WX 546 ; N afii10062 ; B 11 0 535 878 ;
-C -1 ; WX 595 ; N afii10145 ; B 61 -120 528 718 ;
-C -1 ; WX 456 ; N uni0450 ; B 33 -15 423 764 ;
-C -1 ; WX 495 ; N afii10099 ; B 12 -150 442 718 ;
-C -1 ; WX 337 ; N afii10100 ; B 51 0 325 739 ;
-C -1 ; WX 426 ; N afii10101 ; B 29 -15 395 538 ;
-C -1 ; WX 410 ; N afii10102 ; B 26 -15 380 538 ;
-C -1 ; WX 182 ; N afii10103 ; B 55 0 127 718 ;
-C -1 ; WX 317 ; N afii10104 ; B 55 0 262 706 ;
-C -1 ; WX 182 ; N afii10105 ; B -13 -210 127 718 ;
-C -1 ; WX 709 ; N afii10106 ; B 21 0 684 523 ;
-C -1 ; WX 722 ; N afii10107 ; B 53 0 697 523 ;
-C -1 ; WX 495 ; N afii10108 ; B 12 0 442 718 ;
-C -1 ; WX 417 ; N afii10109 ; B 53 0 409 739 ;
-C -1 ; WX 455 ; N uni045D ; B 53 0 403 739 ;
-C -1 ; WX 416 ; N afii10110 ; B 12 -214 404 741 ;
-C -1 ; WX 455 ; N afii10193 ; B 53 -125 403 523 ;
-C -1 ; WX 537 ; N uni048C ; B 8 0 500 718 ;
-C -1 ; WX 444 ; N uni048D ; B 7 0 419 523 ;
-C -1 ; WX 547 ; N uni048E ; B 61 0 532 718 ;
-C -1 ; WX 456 ; N uni048F ; B 48 -207 442 538 ;
-C -1 ; WX 499 ; N afii10050 ; B 67 0 474 799 ;
-C -1 ; WX 344 ; N afii10098 ; B 55 0 329 591 ;
-C -1 ; WX 489 ; N uni0492 ; B 0 0 468 718 ;
-C -1 ; WX 337 ; N uni0493 ; B 0 0 325 523 ;
-C -1 ; WX 543 ; N uni0494 ; B 61 -131 481 718 ;
-C -1 ; WX 407 ; N uni0495 ; B 51 -184 361 523 ;
-C -1 ; WX 902 ; N uni0496 ; B 9 -120 893 718 ;
-C -1 ; WX 658 ; N uni0497 ; B 8 -125 650 523 ;
-C -1 ; WX 541 ; N uni0498 ; B 42 -225 510 737 ;
-C -1 ; WX 410 ; N uni0499 ; B 24 -225 378 538 ;
-C -1 ; WX 552 ; N uni049A ; B 61 -120 543 718 ;
-C -1 ; WX 417 ; N uni049B ; B 53 -125 409 523 ;
-C -1 ; WX 552 ; N uni049C ; B 61 0 543 718 ;
-C -1 ; WX 417 ; N uni049D ; B 53 0 409 523 ;
-C -1 ; WX 598 ; N uni049E ; B 12 0 589 718 ;
-C -1 ; WX 427 ; N uni049F ; B 12 0 419 523 ;
-C -1 ; WX 726 ; N uni04A0 ; B 12 0 715 718 ;
-C -1 ; WX 495 ; N uni04A1 ; B 17 0 487 523 ;
-C -1 ; WX 595 ; N uni04A2 ; B 61 -120 599 718 ;
-C -1 ; WX 455 ; N uni04A3 ; B 53 -125 455 523 ;
-C -1 ; WX 842 ; N uni04A4 ; B 61 0 821 718 ;
-C -1 ; WX 613 ; N uni04A5 ; B 53 0 592 523 ;
-C -1 ; WX 927 ; N uni04A6 ; B 61 -131 865 718 ;
-C -1 ; WX 687 ; N uni04A7 ; B 53 -184 641 523 ;
-C -1 ; WX 588 ; N uni04A8 ; B 32 -19 588 737 ;
-C -1 ; WX 410 ; N uni04A9 ; B 25 -15 406 538 ;
-C -1 ; WX 588 ; N uni04AA ; B 32 -225 554 737 ;
-C -1 ; WX 410 ; N uni04AB ; B 25 -225 391 538 ;
-C -1 ; WX 503 ; N uni04AC ; B 12 -120 491 718 ;
-C -1 ; WX 336 ; N uni04AD ; B 12 -125 324 523 ;
-C -1 ; WX 547 ; N uni04AE ; B 11 0 535 718 ;
-C -1 ; WX 547 ; N uni04AF ; B 41 -195 505 523 ;
-C -1 ; WX 547 ; N uni04B0 ; B 11 0 535 718 ;
-C -1 ; WX 547 ; N uni04B1 ; B 41 -195 505 523 ;
-C -1 ; WX 539 ; N uni04B2 ; B 12 -120 527 718 ;
-C -1 ; WX 410 ; N uni04B3 ; B 8 -125 401 523 ;
-C -1 ; WX 766 ; N uni04B4 ; B 12 -120 745 718 ;
-C -1 ; WX 581 ; N uni04B5 ; B 12 -125 560 523 ;
-C -1 ; WX 597 ; N uni04B6 ; B 62 -120 576 718 ;
-C -1 ; WX 469 ; N uni04B7 ; B 53 -125 448 523 ;
-C -1 ; WX 547 ; N uni04B8 ; B 62 0 480 718 ;
-C -1 ; WX 406 ; N uni04B9 ; B 53 0 371 523 ;
-C -1 ; WX 547 ; N uni04BA ; B 62 0 480 718 ;
-C -1 ; WX 406 ; N uni04BB ; B 53 0 371 523 ;
-C -1 ; WX 822 ; N uni04BC ; B 20 -19 790 737 ;
-C -1 ; WX 603 ; N uni04BD ; B 23 -15 570 538 ;
-C -1 ; WX 822 ; N uni04BE ; B 20 -225 790 737 ;
-C -1 ; WX 603 ; N uni04BF ; B 23 -225 570 538 ;
-C -1 ; WX 228 ; N uni04C0 ; B 75 0 154 718 ;
-C -1 ; WX 902 ; N uni04C1 ; B 9 0 893 954 ;
-C -1 ; WX 658 ; N uni04C2 ; B 8 0 650 759 ;
-C -1 ; WX 552 ; N uni04C3 ; B 61 -131 537 718 ;
-C -1 ; WX 417 ; N uni04C4 ; B 53 -184 399 523 ;
-C -1 ; WX 595 ; N uni04C7 ; B 61 -131 528 718 ;
-C -1 ; WX 455 ; N uni04C8 ; B 53 -184 403 523 ;
-C -1 ; WX 546 ; N uni04CB ; B 62 -120 480 718 ;
-C -1 ; WX 406 ; N uni04CC ; B 53 -125 371 523 ;
-C -1 ; WX 547 ; N uni04D0 ; B 11 0 536 954 ;
-C -1 ; WX 456 ; N uni04D1 ; B 30 -15 435 759 ;
-C -1 ; WX 547 ; N uni04D2 ; B 11 0 536 920 ;
-C -1 ; WX 456 ; N uni04D3 ; B 30 -15 435 725 ;
-C -1 ; WX 820 ; N uni04D4 ; B 7 0 780 718 ;
-C -1 ; WX 729 ; N uni04D5 ; B 30 -15 695 538 ;
-C -1 ; WX 537 ; N uni04D6 ; B 61 0 495 954 ;
-C -1 ; WX 456 ; N uni04D7 ; B 33 -15 423 759 ;
-C -1 ; WX 638 ; N uni04D8 ; B 38 -19 606 737 ;
-C -1 ; WX 456 ; N afii10846 ; B 33 -15 423 538 ;
-C -1 ; WX 638 ; N uni04DA ; B 38 -19 606 859 ;
-C -1 ; WX 456 ; N uni04DB ; B 33 -15 423 660 ;
-C -1 ; WX 902 ; N uni04DC ; B 9 0 893 920 ;
-C -1 ; WX 658 ; N uni04DD ; B 8 0 650 725 ;
-C -1 ; WX 541 ; N uni04DE ; B 42 -19 510 920 ;
-C -1 ; WX 410 ; N uni04DF ; B 24 -15 378 725 ;
-C -1 ; WX 541 ; N uni04E0 ; B 42 -19 510 718 ;
-C -1 ; WX 410 ; N uni04E1 ; B 24 -15 378 523 ;
-C -1 ; WX 596 ; N uni04E2 ; B 61 0 529 854 ;
-C -1 ; WX 455 ; N uni04E3 ; B 53 0 403 655 ;
-C -1 ; WX 596 ; N uni04E4 ; B 61 0 529 899 ;
-C -1 ; WX 455 ; N uni04E5 ; B 53 0 403 700 ;
-C -1 ; WX 638 ; N uni04E6 ; B 32 -19 606 920 ;
-C -1 ; WX 456 ; N uni04E7 ; B 29 -14 427 725 ;
-C -1 ; WX 638 ; N uni04E8 ; B 32 -19 606 737 ;
-C -1 ; WX 456 ; N uni04E9 ; B 29 -14 427 538 ;
-C -1 ; WX 638 ; N uni04EA ; B 32 -19 606 920 ;
-C -1 ; WX 456 ; N uni04EB ; B 29 -14 427 725 ;
-C -1 ; WX 590 ; N uni04EC ; B 32 -19 554 920 ;
-C -1 ; WX 410 ; N uni04ED ; B 25 -15 391 725 ;
-C -1 ; WX 548 ; N uni04EE ; B 12 0 536 875 ;
-C -1 ; WX 409 ; N uni04EF ; B 8 -214 400 680 ;
-C -1 ; WX 548 ; N uni04F0 ; B 12 0 536 920 ;
-C -1 ; WX 409 ; N uni04F1 ; B 8 -214 400 725 ;
-C -1 ; WX 548 ; N uni04F2 ; B 12 0 536 959 ;
-C -1 ; WX 409 ; N uni04F3 ; B 8 -214 400 764 ;
-C -1 ; WX 547 ; N uni04F4 ; B 62 0 480 899 ;
-C -1 ; WX 406 ; N uni04F5 ; B 53 0 371 700 ;
-C -1 ; WX 783 ; N uni04F8 ; B 61 0 716 920 ;
-C -1 ; WX 585 ; N uni04F9 ; B 53 0 533 725 ;
-C -1 ; WX 337 ; N uniF6C4 ; B 51 0 325 523 ;
-C -1 ; WX 442 ; N uniF6C5 ; B 26 -14 424 776 ;
-C -1 ; WX 536 ; N uniF6C6 ; B 21 -125 515 523 ;
-C -1 ; WX 455 ; N uniF6C7 ; B 53 0 403 523 ;
-C -1 ; WX 336 ; N uniF6C8 ; B 12 0 324 523 ;
-C -1 ; WX 592 ; N Ccircumflex ; B 36 -19 558 959 ;
-C -1 ; WX 410 ; N ccircumflex ; B 25 -15 391 764 ;
-C -1 ; WX 592 ; N Cdotaccent ; B 36 -19 558 920 ;
-C -1 ; WX 410 ; N cdotaccent ; B 25 -15 391 725 ;
-C -1 ; WX 547 ; N Ebreve ; B 71 0 505 954 ;
-C -1 ; WX 456 ; N ebreve ; B 33 -15 423 759 ;
-C -1 ; WX 638 ; N Gcircumflex ; B 39 -19 577 959 ;
-C -1 ; WX 456 ; N gcircumflex ; B 33 -220 409 764 ;
-C -1 ; WX 638 ; N Gdotaccent ; B 39 -19 577 920 ;
-C -1 ; WX 456 ; N gdotaccent ; B 33 -220 409 725 ;
-C -1 ; WX 592 ; N Hcircumflex ; B 63 0 530 959 ;
-C -1 ; WX 456 ; N hcircumflex ; B -31 0 403 959 ;
-C -1 ; WX 645 ; N Hbar ; B 16 0 629 718 ;
-C -1 ; WX 490 ; N hbar ; B 16 0 437 718 ;
-C -1 ; WX 228 ; N Itilde ; B -25 0 254 934 ;
-C -1 ; WX 228 ; N itilde ; B -25 0 254 739 ;
-C -1 ; WX 228 ; N Ibreve ; B -11 0 241 954 ;
-C -1 ; WX 228 ; N ibreve ; B -12 0 240 759 ;
-C -1 ; WX 644 ; N IJ ; B 75 -19 566 718 ;
-C -1 ; WX 308 ; N ij ; B 55 -210 254 718 ;
-C -1 ; WX 410 ; N Jcircumflex ; B 14 -19 430 959 ;
-C -1 ; WX 182 ; N jcircumflex ; B -13 -210 256 734 ;
-C -1 ; WX 417 ; N kgreenlandic ; B 53 0 409 523 ;
-C -1 ; WX 456 ; N Ldot ; B 62 0 440 718 ;
-C -1 ; WX 410 ; N ldot ; B 55 0 348 718 ;
-C -1 ; WX 456 ; N napostrophe ; B 52 0 403 827 ;
-C -1 ; WX 592 ; N Eng ; B 62 -131 530 718 ;
-C -1 ; WX 456 ; N eng ; B 53 -184 403 538 ;
-C -1 ; WX 638 ; N Obreve ; B 32 -19 606 954 ;
-C -1 ; WX 456 ; N obreve ; B 29 -14 427 759 ;
-C -1 ; WX 547 ; N Scircumflex ; B 40 -19 508 959 ;
-C -1 ; WX 410 ; N scircumflex ; B 26 -15 380 764 ;
-C -1 ; WX 501 ; N Tbar ; B 11 0 490 718 ;
-C -1 ; WX 228 ; N tbar ; B 11 -7 213 669 ;
-C -1 ; WX 592 ; N Utilde ; B 65 -19 528 934 ;
-C -1 ; WX 456 ; N utilde ; B 56 -15 401 739 ;
-C -1 ; WX 592 ; N Ubreve ; B 65 -19 528 954 ;
-C -1 ; WX 456 ; N ubreve ; B 56 -15 401 759 ;
-C -1 ; WX 774 ; N Wcircumflex ; B 13 0 761 959 ;
-C -1 ; WX 592 ; N wcircumflex ; B 11 0 581 764 ;
-C -1 ; WX 547 ; N Ycircumflex ; B 11 0 535 959 ;
-C -1 ; WX 410 ; N ycircumflex ; B 9 -214 401 764 ;
-C -1 ; WX 228 ; N longs ; B 11 0 215 728 ;
-C -1 ; WX 827 ; N afii61352 ; B 62 0 800 718 ;
-C -1 ; WX 680 ; N infinity ; B 20 166 660 518 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 978
-KPX quoteright A -60
-KPX quoteright AE -63
-KPX quoteright Aacute -60
-KPX quoteright Adieresis -60
-KPX quoteright Aring -60
-KPX quoteright comma -48
-KPX quoteright d -16
-KPX quoteright o -24
-KPX quoteright period -48
-KPX quoteright r -15
-KPX quoteright s -13
-KPX quoteright t -3
-KPX quoteright w 1
-KPX comma one -83
-KPX comma quotedblright -22
-KPX comma quoteright -33
-KPX hyphen A -3
-KPX hyphen AE -4
-KPX hyphen Aacute -3
-KPX hyphen Adieresis -3
-KPX hyphen Aring -3
-KPX hyphen T -61
-KPX hyphen V -29
-KPX hyphen W -9
-KPX hyphen Y -67
-KPX period one -83
-KPX period quotedblright -22
-KPX period quoteright -33
-KPX zero four 5
-KPX zero one -31
-KPX zero seven -21
-KPX one comma -54
-KPX one eight -46
-KPX one five -49
-KPX one four -59
-KPX one nine -47
-KPX one one -90
-KPX one period -54
-KPX one seven -64
-KPX one six -44
-KPX one three -51
-KPX one two -50
-KPX one zero -43
-KPX two four -38
-KPX two one -29
-KPX two seven -14
-KPX three four 8
-KPX three one -34
-KPX three seven -15
-KPX four four 8
-KPX four one -65
-KPX four seven -39
-KPX five four 4
-KPX five one -56
-KPX five seven -16
-KPX six four 6
-KPX six one -31
-KPX six seven -13
-KPX seven colon -47
-KPX seven comma -95
-KPX seven eight -15
-KPX seven five -22
-KPX seven four -72
-KPX seven one -34
-KPX seven period -95
-KPX seven seven 3
-KPX seven six -24
-KPX seven three -14
-KPX seven two -14
-KPX eight four 6
-KPX eight one -36
-KPX eight seven -16
-KPX nine four 1
-KPX nine one -31
-KPX nine seven -19
-KPX A C -28
-KPX A Ccedilla -29
-KPX A G -30
-KPX A O -27
-KPX A Odieresis -27
-KPX A Q -28
-KPX A T -74
-KPX A U -29
-KPX A Uacute -29
-KPX A Ucircumflex -29
-KPX A Udieresis -29
-KPX A Ugrave -29
-KPX A V -56
-KPX A W -39
-KPX A Y -78
-KPX A a -3
-KPX A c -10
-KPX A ccedilla -10
-KPX A comma 5
-KPX A d -11
-KPX A e -14
-KPX A g -14
-KPX A guillemotleft -40
-KPX A guilsinglleft -36
-KPX A hyphen -2
-KPX A o -13
-KPX A period 5
-KPX A q -11
-KPX A quotedblright -37
-KPX A quoteright -48
-KPX A t -15
-KPX A u -12
-KPX A v -27
-KPX A w -21
-KPX A y -27
-KPX B A -15
-KPX B AE -14
-KPX B Aacute -15
-KPX B Acircumflex -15
-KPX B Adieresis -15
-KPX B Aring -15
-KPX B Atilde -15
-KPX B O -3
-KPX B Oacute -3
-KPX B Ocircumflex -3
-KPX B Odieresis -3
-KPX B Ograve -3
-KPX B V -25
-KPX B W -14
-KPX B Y -31
-KPX C A -25
-KPX C AE -24
-KPX C Aacute -25
-KPX C Adieresis -25
-KPX C Aring -25
-KPX C H -6
-KPX C K -5
-KPX C O -4
-KPX C Oacute -4
-KPX C Odieresis -4
-KPX D A -33
-KPX D Aacute -33
-KPX D Acircumflex -33
-KPX D Adieresis -33
-KPX D Agrave -33
-KPX D Aring -33
-KPX D Atilde -33
-KPX D J -1
-KPX D T -30
-KPX D V -32
-KPX D W -18
-KPX D X -38
-KPX D Y -44
-KPX F A -55
-KPX F Aacute -55
-KPX F Acircumflex -55
-KPX F Adieresis -55
-KPX F Agrave -55
-KPX F Aring -55
-KPX F Atilde -55
-KPX F J -50
-KPX F O -15
-KPX F Odieresis -15
-KPX F a -26
-KPX F aacute -26
-KPX F adieresis -26
-KPX F ae -26
-KPX F aring -26
-KPX F comma -102
-KPX F e -19
-KPX F eacute -19
-KPX F hyphen -12
-KPX F i -8
-KPX F j -8
-KPX F o -17
-KPX F oacute -17
-KPX F odieresis -17
-KPX F oe -17
-KPX F oslash -17
-KPX F period -102
-KPX F r -32
-KPX F u -28
-KPX G A -4
-KPX G AE -2
-KPX G Aacute -4
-KPX G Acircumflex -4
-KPX G Adieresis -4
-KPX G Agrave -4
-KPX G Aring -4
-KPX G Atilde -4
-KPX G T -30
-KPX G V -36
-KPX G W -20
-KPX G Y -47
-KPX J A -22
-KPX J AE -21
-KPX J Adieresis -22
-KPX J Aring -22
-KPX K C -37
-KPX K G -40
-KPX K O -37
-KPX K OE -33
-KPX K Oacute -37
-KPX K Odieresis -37
-KPX K S -27
-KPX K T 22
-KPX K a -6
-KPX K adieresis -6
-KPX K ae -7
-KPX K aring -6
-KPX K e -26
-KPX K hyphen -38
-KPX K o -26
-KPX K oacute -26
-KPX K odieresis -26
-KPX K u -21
-KPX K udieresis -21
-KPX K y -52
-KPX L A 18
-KPX L AE 20
-KPX L Aacute 18
-KPX L Adieresis 18
-KPX L Aring 18
-KPX L C -28
-KPX L Ccedilla -32
-KPX L G -31
-KPX L O -29
-KPX L Oacute -29
-KPX L Ocircumflex -29
-KPX L Odieresis -29
-KPX L Ograve -29
-KPX L Otilde -29
-KPX L S -11
-KPX L T -81
-KPX L U -25
-KPX L Udieresis -25
-KPX L V -78
-KPX L W -50
-KPX L Y -92
-KPX L hyphen -110
-KPX L quotedblright -105
-KPX L quoteright -116
-KPX L u -9
-KPX L udieresis -9
-KPX L y -47
-KPX N A -4
-KPX N AE -2
-KPX N Aacute -4
-KPX N Adieresis -4
-KPX N Aring -4
-KPX N G -1
-KPX N O 1
-KPX N Oacute 1
-KPX N Odieresis 1
-KPX N a -1
-KPX N aacute -1
-KPX N adieresis -1
-KPX N ae -1
-KPX N aring -1
-KPX N comma -4
-KPX N e 1
-KPX N eacute 1
-KPX N o 1
-KPX N oacute 1
-KPX N odieresis 1
-KPX N oslash 4
-KPX N period -4
-KPX O A -29
-KPX O AE -29
-KPX O Aacute -29
-KPX O Adieresis -29
-KPX O Aring -29
-KPX O T -27
-KPX O V -30
-KPX O W -14
-KPX O X -35
-KPX O Y -42
-KPX P A -62
-KPX P AE -64
-KPX P Aacute -62
-KPX P Adieresis -62
-KPX P Aring -62
-KPX P J -70
-KPX P a -21
-KPX P aacute -21
-KPX P adieresis -21
-KPX P ae -21
-KPX P aring -21
-KPX P comma -123
-KPX P e -24
-KPX P eacute -24
-KPX P hyphen -28
-KPX P o -24
-KPX P oacute -24
-KPX P odieresis -24
-KPX P oe -22
-KPX P oslash -22
-KPX P period -123
-KPX R C -7
-KPX R Ccedilla -7
-KPX R G -9
-KPX R O -6
-KPX R OE -3
-KPX R Oacute -6
-KPX R Odieresis -6
-KPX R T -12
-KPX R U -8
-KPX R Udieresis -8
-KPX R V -22
-KPX R W -15
-KPX R Y -29
-KPX R a -6
-KPX R aacute -6
-KPX R adieresis -6
-KPX R ae -6
-KPX R aring -6
-KPX R e -5
-KPX R eacute -5
-KPX R hyphen 4
-KPX R o -5
-KPX R oacute -5
-KPX R odieresis -5
-KPX R oe -5
-KPX R u -4
-KPX R uacute -5
-KPX R udieresis -5
-KPX R y -1
-KPX S A -15
-KPX S AE -14
-KPX S Aacute -15
-KPX S Adieresis -15
-KPX S Aring -15
-KPX S T -14
-KPX S V -25
-KPX S W -17
-KPX S Y -31
-KPX S t -2
-KPX T A -78
-KPX T AE -76
-KPX T Aacute -78
-KPX T Acircumflex -78
-KPX T Adieresis -78
-KPX T Agrave -78
-KPX T Aring -78
-KPX T Atilde -78
-KPX T C -27
-KPX T G -31
-KPX T J -80
-KPX T O -26
-KPX T OE -22
-KPX T Oacute -26
-KPX T Ocircumflex -26
-KPX T Odieresis -26
-KPX T Ograve -26
-KPX T Oslash -27
-KPX T Otilde -26
-KPX T S -15
-KPX T V 17
-KPX T W 19
-KPX T Y 19
-KPX T a -79
-KPX T ae -79
-KPX T c -73
-KPX T colon -95
-KPX T comma -80
-KPX T e -77
-KPX T g -76
-KPX T guillemotleft -100
-KPX T guilsinglleft -96
-KPX T hyphen -60
-KPX T i -2
-KPX T j -2
-KPX T o -76
-KPX T oslash -72
-KPX T period -80
-KPX T r -77
-KPX T s -74
-KPX T semicolon -93
-KPX T u -75
-KPX T v -79
-KPX T w -80
-KPX T y -79
-KPX U A -32
-KPX U AE -32
-KPX U Aacute -32
-KPX U Acircumflex -32
-KPX U Adieresis -32
-KPX U Aring -32
-KPX U Atilde -32
-KPX U comma -24
-KPX U m -1
-KPX U n -1
-KPX U period -22
-KPX U r -6
-KPX V A -58
-KPX V AE -60
-KPX V Aacute -58
-KPX V Acircumflex -58
-KPX V Adieresis -58
-KPX V Agrave -58
-KPX V Aring -58
-KPX V Atilde -58
-KPX V C -31
-KPX V G -34
-KPX V O -30
-KPX V Oacute -30
-KPX V Ocircumflex -30
-KPX V Odieresis -30
-KPX V Ograve -30
-KPX V Oslash -27
-KPX V Otilde -30
-KPX V S -26
-KPX V T 18
-KPX V a -47
-KPX V ae -47
-KPX V colon -41
-KPX V comma -73
-KPX V e -46
-KPX V g -44
-KPX V guillemotleft -68
-KPX V guilsinglleft -64
-KPX V hyphen -29
-KPX V i -5
-KPX V o -46
-KPX V oslash -41
-KPX V period -73
-KPX V r -37
-KPX V semicolon -41
-KPX V u -35
-KPX V y -12
-KPX W A -42
-KPX W AE -43
-KPX W Aacute -42
-KPX W Acircumflex -42
-KPX W Adieresis -42
-KPX W Agrave -42
-KPX W Aring -42
-KPX W Atilde -42
-KPX W C -15
-KPX W G -18
-KPX W O -14
-KPX W Oacute -14
-KPX W Ocircumflex -14
-KPX W Odieresis -14
-KPX W Ograve -14
-KPX W Oslash -12
-KPX W Otilde -14
-KPX W S -19
-KPX W T 20
-KPX W a -29
-KPX W ae -29
-KPX W colon -31
-KPX W comma -46
-KPX W e -26
-KPX W g -24
-KPX W guillemotleft -48
-KPX W guilsinglleft -44
-KPX W hyphen -9
-KPX W i -3
-KPX W o -26
-KPX W oslash -21
-KPX W period -46
-KPX W r -26
-KPX W semicolon -31
-KPX W u -24
-KPX W y -2
-KPX X C -33
-KPX X O -33
-KPX X Odieresis -33
-KPX X Q -33
-KPX X a -12
-KPX X e -31
-KPX X hyphen -40
-KPX X o -31
-KPX X u -27
-KPX X y -42
-KPX Y A -80
-KPX Y AE -82
-KPX Y Aacute -80
-KPX Y Acircumflex -80
-KPX Y Adieresis -80
-KPX Y Agrave -80
-KPX Y Aring -80
-KPX Y Atilde -80
-KPX Y C -43
-KPX Y G -47
-KPX Y O -43
-KPX Y Oacute -43
-KPX Y Ocircumflex -43
-KPX Y Odieresis -43
-KPX Y Ograve -43
-KPX Y Oslash -44
-KPX Y Otilde -43
-KPX Y S -33
-KPX Y T 20
-KPX Y a -73
-KPX Y ae -73
-KPX Y colon -60
-KPX Y comma -92
-KPX Y e -74
-KPX Y g -73
-KPX Y guillemotleft -103
-KPX Y guilsinglleft -99
-KPX Y hyphen -68
-KPX Y i -3
-KPX Y o -74
-KPX Y oslash -69
-KPX Y p -48
-KPX Y period -92
-KPX Y semicolon -60
-KPX Y u -54
-KPX Y v -31
-KPX Z v -24
-KPX Z y -25
-KPX quoteleft A -52
-KPX quoteleft AE -55
-KPX quoteleft Aacute -52
-KPX quoteleft Adieresis -52
-KPX quoteleft Aring -52
-KPX quoteleft T 5
-KPX quoteleft V 13
-KPX quoteleft W 20
-KPX quoteleft Y 3
-KPX a j -5
-KPX a quoteright -10
-KPX a v -19
-KPX a w -14
-KPX a y -20
-KPX b v -13
-KPX b w -8
-KPX b y -15
-KPX c h 2
-KPX c k 1
-KPX e quoteright -5
-KPX e t -8
-KPX e v -16
-KPX e w -11
-KPX e x -19
-KPX e y -18
-KPX f a -9
-KPX f aacute -9
-KPX f adieresis -9
-KPX f ae -9
-KPX f aring -9
-KPX f e -12
-KPX f eacute -12
-KPX f f 17
-KPX f i -5
-KPX f j -5
-KPX f l -5
-KPX f o -12
-KPX f oacute -12
-KPX f odieresis -12
-KPX f oe -12
-KPX f oslash -8
-KPX f quoteright 12
-KPX f s -4
-KPX f t 17
-KPX g a 1
-KPX g adieresis 1
-KPX g ae 1
-KPX g aring 1
-KPX g e 4
-KPX g eacute 4
-KPX g l 4
-KPX g oacute 4
-KPX g odieresis 4
-KPX h quoteright -3
-KPX h y -14
-KPX i T -2
-KPX k a -5
-KPX k aacute -5
-KPX k adieresis -5
-KPX k ae -5
-KPX k aring -5
-KPX k comma 1
-KPX k e -19
-KPX k eacute -19
-KPX k g -18
-KPX k hyphen -31
-KPX k o -19
-KPX k oacute -19
-KPX k odieresis -19
-KPX k period 1
-KPX k s -9
-KPX k u -3
-KPX k udieresis -3
-KPX l v -3
-KPX l y -3
-KPX m p 4
-KPX m v -13
-KPX m w -7
-KPX m y -13
-KPX n T -75
-KPX n p 4
-KPX n quoteright -3
-KPX n v -14
-KPX n w -8
-KPX n y -14
-KPX o T -77
-KPX o quoteright -8
-KPX o t -7
-KPX o v -15
-KPX o w -9
-KPX o x -18
-KPX o y -17
-KPX p t -6
-KPX p y -15
-KPX q c 6
-KPX q u 1
-KPX r a -3
-KPX r aacute -3
-KPX r acircumflex -3
-KPX r adieresis -3
-KPX r ae -3
-KPX r agrave -3
-KPX r aring -3
-KPX r c -6
-KPX r ccedilla -3
-KPX r colon -5
-KPX r comma -48
-KPX r d -4
-KPX r e -10
-KPX r eacute -10
-KPX r ecircumflex -10
-KPX r egrave -10
-KPX r f 23
-KPX r g -4
-KPX r h 2
-KPX r hyphen -30
-KPX r i 1
-KPX r k 1
-KPX r l 1
-KPX r m 2
-KPX r n 2
-KPX r o -11
-KPX r oacute -11
-KPX r ocircumflex -11
-KPX r odieresis -11
-KPX r oe -7
-KPX r ograve -11
-KPX r oslash -7
-KPX r p 4
-KPX r period -48
-KPX r q -4
-KPX r quoteright 14
-KPX r r -3
-KPX r s 2
-KPX r semicolon -5
-KPX r t 23
-KPX r v 24
-KPX r w 22
-KPX r x 19
-KPX r y 23
-KPX r z 6
-KPX s quoteright -5
-KPX s t -5
-KPX t S -8
-KPX t a 1
-KPX t aacute 1
-KPX t adieresis 1
-KPX t ae 1
-KPX t aring 1
-KPX t colon -13
-KPX t e -10
-KPX t eacute -10
-KPX t h 1
-KPX t o -10
-KPX t oacute -10
-KPX t odieresis -10
-KPX t quoteright 10
-KPX t semicolon -13
-KPX u quoteright 5
-KPX v a -16
-KPX v aacute -16
-KPX v acircumflex -16
-KPX v adieresis -16
-KPX v ae -16
-KPX v agrave -16
-KPX v aring -16
-KPX v atilde -16
-KPX v c -12
-KPX v colon -8
-KPX v comma -50
-KPX v e -16
-KPX v eacute -16
-KPX v ecircumflex -16
-KPX v egrave -16
-KPX v g -15
-KPX v hyphen -3
-KPX v l -2
-KPX v o -16
-KPX v oacute -16
-KPX v odieresis -16
-KPX v ograve -16
-KPX v oslash -12
-KPX v period -50
-KPX v s -10
-KPX v semicolon -8
-KPX w a -13
-KPX w aacute -13
-KPX w acircumflex -13
-KPX w adieresis -13
-KPX w ae -13
-KPX w agrave -13
-KPX w aring -13
-KPX w atilde -13
-KPX w c -5
-KPX w colon -10
-KPX w comma -37
-KPX w e -9
-KPX w eacute -9
-KPX w ecircumflex -9
-KPX w egrave -9
-KPX w g -8
-KPX w hyphen 3
-KPX w l -4
-KPX w o -9
-KPX w oacute -9
-KPX w odieresis -9
-KPX w ograve -9
-KPX w oslash -5
-KPX w period -37
-KPX w s -7
-KPX w semicolon -10
-KPX x a -10
-KPX x c -13
-KPX x e -17
-KPX x eacute -17
-KPX x o -17
-KPX x q -14
-KPX y a -16
-KPX y aacute -16
-KPX y acircumflex -16
-KPX y adieresis -16
-KPX y ae -16
-KPX y agrave -16
-KPX y aring -16
-KPX y atilde -16
-KPX y c -13
-KPX y colon -9
-KPX y comma -49
-KPX y e -17
-KPX y eacute -17
-KPX y ecircumflex -17
-KPX y egrave -17
-KPX y g -15
-KPX y hyphen -2
-KPX y l -3
-KPX y o -16
-KPX y oacute -16
-KPX y odieresis -16
-KPX y ograve -16
-KPX y oslash -12
-KPX y period -49
-KPX y s -11
-KPX y semicolon -9
-KPX quotedblleft A -41
-KPX quotedblleft AE -44
-KPX quotedblleft Aacute -41
-KPX quotedblleft Adieresis -41
-KPX quotedblleft Aring -41
-KPX quotedblleft T 16
-KPX quotedblleft V 24
-KPX quotedblleft W 31
-KPX quotedblleft Y 14
-KPX guilsinglright A -38
-KPX guilsinglright AE -39
-KPX guilsinglright Aacute -38
-KPX guilsinglright Adieresis -38
-KPX guilsinglright Aring -38
-KPX guilsinglright T -96
-KPX guilsinglright V -64
-KPX guilsinglright W -43
-KPX guilsinglright Y -98
-KPX quotedblbase A 24
-KPX quotedblbase AE 25
-KPX quotedblbase T -60
-KPX quotedblbase V -53
-KPX quotedblbase W -25
-KPX quotedblbase Y -71
-KPX quotedblright A -49
-KPX quotedblright AE -52
-KPX quotedblright Aacute -49
-KPX quotedblright Adieresis -49
-KPX quotedblright Aring -49
-KPX quotedblright T 11
-KPX quotedblright V 16
-KPX quotedblright W 23
-KPX quotedblright Y 9
-KPX guillemotright A -42
-KPX guillemotright AE -43
-KPX guillemotright Aacute -42
-KPX guillemotright Adieresis -42
-KPX guillemotright Aring -42
-KPX guillemotright T -101
-KPX guillemotright V -68
-KPX guillemotright W -48
-KPX guillemotright Y -102
-KPX Oslash A -27
-KPX ae v -17
-KPX ae w -11
-KPX ae y -19
-KPX Adieresis C -28
-KPX Adieresis G -30
-KPX Adieresis O -27
-KPX Adieresis Q -28
-KPX Adieresis T -74
-KPX Adieresis U -29
-KPX Adieresis V -56
-KPX Adieresis W -39
-KPX Adieresis Y -78
-KPX Adieresis a -3
-KPX Adieresis c -10
-KPX Adieresis comma 5
-KPX Adieresis d -11
-KPX Adieresis g -14
-KPX Adieresis guillemotleft -40
-KPX Adieresis guilsinglleft -36
-KPX Adieresis hyphen -2
-KPX Adieresis o -13
-KPX Adieresis period 5
-KPX Adieresis q -11
-KPX Adieresis quotedblright -37
-KPX Adieresis quoteright -48
-KPX Adieresis t -15
-KPX Adieresis u -12
-KPX Adieresis v -27
-KPX Adieresis w -21
-KPX Adieresis y -27
-KPX Aacute C -28
-KPX Aacute G -30
-KPX Aacute O -27
-KPX Aacute Q -28
-KPX Aacute T -74
-KPX Aacute U -29
-KPX Aacute V -56
-KPX Aacute W -39
-KPX Aacute Y -78
-KPX Aacute a -3
-KPX Aacute c -10
-KPX Aacute comma 5
-KPX Aacute d -11
-KPX Aacute e -14
-KPX Aacute g -14
-KPX Aacute guillemotleft -40
-KPX Aacute guilsinglleft -36
-KPX Aacute hyphen -2
-KPX Aacute o -13
-KPX Aacute period 5
-KPX Aacute q -11
-KPX Aacute quoteright -48
-KPX Aacute t -15
-KPX Aacute u -12
-KPX Aacute v -27
-KPX Aacute w -21
-KPX Aacute y -27
-KPX Agrave C -28
-KPX Agrave G -30
-KPX Agrave O -27
-KPX Agrave Q -28
-KPX Agrave T -74
-KPX Agrave U -29
-KPX Agrave V -56
-KPX Agrave W -39
-KPX Agrave Y -78
-KPX Agrave comma 5
-KPX Agrave period 5
-KPX Acircumflex C -28
-KPX Acircumflex G -30
-KPX Acircumflex O -27
-KPX Acircumflex Q -28
-KPX Acircumflex T -74
-KPX Acircumflex U -29
-KPX Acircumflex V -56
-KPX Acircumflex W -39
-KPX Acircumflex Y -78
-KPX Acircumflex comma 5
-KPX Acircumflex period 5
-KPX Atilde C -28
-KPX Atilde G -30
-KPX Atilde O -27
-KPX Atilde Q -28
-KPX Atilde T -74
-KPX Atilde U -29
-KPX Atilde V -56
-KPX Atilde W -39
-KPX Atilde Y -78
-KPX Atilde comma 5
-KPX Atilde period 5
-KPX Aring C -28
-KPX Aring G -30
-KPX Aring O -27
-KPX Aring Q -28
-KPX Aring T -74
-KPX Aring U -29
-KPX Aring V -56
-KPX Aring W -39
-KPX Aring Y -78
-KPX Aring a -3
-KPX Aring c -10
-KPX Aring comma 5
-KPX Aring d -11
-KPX Aring e -14
-KPX Aring g -14
-KPX Aring guillemotleft -40
-KPX Aring guilsinglleft -36
-KPX Aring hyphen -2
-KPX Aring o -13
-KPX Aring period 5
-KPX Aring q -11
-KPX Aring quotedblright -37
-KPX Aring quoteright -48
-KPX Aring t -15
-KPX Aring u -12
-KPX Aring v -27
-KPX Aring w -21
-KPX Aring y -27
-KPX Ccedilla A -28
-KPX Odieresis A -29
-KPX Odieresis T -27
-KPX Odieresis V -30
-KPX Odieresis W -14
-KPX Odieresis X -35
-KPX Odieresis Y -42
-KPX Oacute A -29
-KPX Oacute T -27
-KPX Oacute V -30
-KPX Oacute W -14
-KPX Oacute Y -42
-KPX Ograve T -27
-KPX Ograve V -30
-KPX Ograve Y -42
-KPX Ocircumflex T -27
-KPX Ocircumflex V -30
-KPX Ocircumflex Y -42
-KPX Otilde T -27
-KPX Otilde V -30
-KPX Otilde Y -42
-KPX Udieresis A -32
-KPX Udieresis comma -24
-KPX Udieresis m -1
-KPX Udieresis n -1
-KPX Udieresis period -22
-KPX Udieresis r -6
-KPX Uacute A -32
-KPX Uacute comma -24
-KPX Uacute m -1
-KPX Uacute n -1
-KPX Uacute period -22
-KPX Uacute r -6
-KPX Ugrave A -32
-KPX Ucircumflex A -32
-KPX adieresis v -19
-KPX adieresis w -14
-KPX adieresis y -20
-KPX aacute v -19
-KPX aacute w -14
-KPX aacute y -20
-KPX agrave v -19
-KPX agrave w -14
-KPX agrave y -20
-KPX aring v -19
-KPX aring w -14
-KPX aring y -20
-KPX eacute v -16
-KPX eacute w -11
-KPX eacute y -18
-KPX ecircumflex v -16
-KPX ecircumflex w -11
-KPX ecircumflex y -18
-KPX odieresis t -7
-KPX odieresis v -15
-KPX odieresis w -9
-KPX odieresis x -18
-KPX odieresis y -17
-KPX oacute v -15
-KPX oacute w -9
-KPX oacute y -17
-KPX ograve v -15
-KPX ograve w -9
-KPX ograve y -17
-KPX ocircumflex t -7
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-sans-l/n019043l.pfb b/src/fonts/nimbus-sans-l/n019043l.pfb
deleted file mode 100644
index 018c885..0000000
--- a/src/fonts/nimbus-sans-l/n019043l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019043l.pfm b/src/fonts/nimbus-sans-l/n019043l.pfm
deleted file mode 100644
index e9167a8..0000000
--- a/src/fonts/nimbus-sans-l/n019043l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019044l.afm b/src/fonts/nimbus-sans-l/n019044l.afm
deleted file mode 100644
index e408b31..0000000
--- a/src/fonts/nimbus-sans-l/n019044l.afm
+++ /dev/null
@@ -1,1556 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 14:45:18 2007
-FontName NimbusSanL-BoldCond
-FullName Nimbus Sans L Bold Condensed
-FamilyName Nimbus Sans L
-Weight Bold
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle 0
-IsFixedPitch false
-UnderlinePosition -100
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -139 -307 878 975
-CapHeight 718
-XHeight 532
-Ascender 718
-Descender -207
-StartCharMetrics 561
-C 32 ; WX 228 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 273 ; N exclam ; B 74 0 200 718 ;
-C 34 ; WX 389 ; N quotedbl ; B 80 447 308 718 ;
-C 35 ; WX 456 ; N numbersign ; B 15 0 441 698 ;
-C 36 ; WX 456 ; N dollar ; B 24 -115 429 775 ;
-C 37 ; WX 729 ; N percent ; B 23 -19 706 710 ;
-C 38 ; WX 592 ; N ampersand ; B 44 -19 575 718 ;
-C 39 ; WX 228 ; N quoteright ; B 57 445 171 718 ;
-C 40 ; WX 273 ; N parenleft ; B 29 -207 257 734 ;
-C 41 ; WX 273 ; N parenright ; B 16 -207 244 734 ;
-C 42 ; WX 319 ; N asterisk ; B 22 387 297 718 ;
-C 43 ; WX 479 ; N plus ; B 33 0 446 506 ;
-C 44 ; WX 228 ; N comma ; B 52 -168 175 147 ;
-C 45 ; WX 273 ; N hyphen ; B 22 215 251 345 ;
-C 46 ; WX 228 ; N period ; B 52 0 175 147 ;
-C 47 ; WX 228 ; N slash ; B -27 -19 255 737 ;
-C 48 ; WX 456 ; N zero ; B 26 -19 430 710 ;
-C 49 ; WX 456 ; N one ; B 57 0 310 710 ;
-C 50 ; WX 456 ; N two ; B 21 0 419 710 ;
-C 51 ; WX 456 ; N three ; B 22 -19 423 710 ;
-C 52 ; WX 456 ; N four ; B 22 0 431 710 ;
-C 53 ; WX 456 ; N five ; B 22 -19 423 698 ;
-C 54 ; WX 456 ; N six ; B 25 -19 426 710 ;
-C 55 ; WX 456 ; N seven ; B 20 0 433 698 ;
-C 56 ; WX 456 ; N eight ; B 26 -19 430 710 ;
-C 57 ; WX 456 ; N nine ; B 25 -19 428 710 ;
-C 58 ; WX 273 ; N colon ; B 75 0 198 512 ;
-C 59 ; WX 273 ; N semicolon ; B 75 -168 198 512 ;
-C 60 ; WX 479 ; N less ; B 31 -15 448 521 ;
-C 61 ; WX 479 ; N equal ; B 33 87 446 419 ;
-C 62 ; WX 479 ; N greater ; B 31 -15 448 521 ;
-C 63 ; WX 501 ; N question ; B 49 0 456 727 ;
-C 64 ; WX 800 ; N at ; B 97 -19 702 737 ;
-C 65 ; WX 592 ; N A ; B 16 0 576 718 ;
-C 66 ; WX 592 ; N B ; B 62 0 549 718 ;
-C 67 ; WX 592 ; N C ; B 36 -19 561 737 ;
-C 68 ; WX 592 ; N D ; B 62 0 562 718 ;
-C 69 ; WX 547 ; N E ; B 62 0 509 718 ;
-C 70 ; WX 501 ; N F ; B 62 0 481 718 ;
-C 71 ; WX 638 ; N G ; B 36 -19 585 737 ;
-C 72 ; WX 592 ; N H ; B 58 0 534 718 ;
-C 73 ; WX 228 ; N I ; B 52 0 175 718 ; L J IJ ;
-C 74 ; WX 456 ; N J ; B 18 -18 397 718 ;
-C 75 ; WX 592 ; N K ; B 71 0 592 718 ;
-C 76 ; WX 501 ; N L ; B 62 0 478 718 ; L periodcentered Ldot ;
-C 77 ; WX 683 ; N M ; B 57 0 627 718 ;
-C 78 ; WX 592 ; N N ; B 57 0 536 718 ; L o afii61352 ;
-C 79 ; WX 638 ; N O ; B 36 -19 602 737 ;
-C 80 ; WX 547 ; N P ; B 62 0 514 718 ;
-C 81 ; WX 638 ; N Q ; B 36 -52 604 737 ;
-C 82 ; WX 592 ; N R ; B 62 0 555 718 ;
-C 83 ; WX 547 ; N S ; B 32 -19 516 737 ;
-C 84 ; WX 501 ; N T ; B 11 0 490 718 ; L M trademark ;
-C 85 ; WX 592 ; N U ; B 59 -19 534 718 ;
-C 86 ; WX 547 ; N V ; B 16 0 531 718 ;
-C 87 ; WX 774 ; N W ; B 13 0 762 718 ;
-C 88 ; WX 547 ; N X ; B 11 0 535 718 ;
-C 89 ; WX 547 ; N Y ; B 12 0 535 718 ;
-C 90 ; WX 501 ; N Z ; B 20 0 481 718 ;
-C 91 ; WX 273 ; N bracketleft ; B 52 -196 253 722 ;
-C 92 ; WX 228 ; N backslash ; B -27 -19 255 737 ;
-C 93 ; WX 273 ; N bracketright ; B 20 -196 221 722 ;
-C 94 ; WX 479 ; N asciicircum ; B 51 323 428 698 ;
-C 95 ; WX 456 ; N underscore ; B 0 -125 456 -75 ;
-C 96 ; WX 228 ; N quoteleft ; B 57 454 171 727 ;
-C 97 ; WX 456 ; N a ; B 24 -14 432 546 ;
-C 98 ; WX 501 ; N b ; B 50 -14 474 718 ;
-C 99 ; WX 456 ; N c ; B 28 -14 430 546 ;
-C 100 ; WX 501 ; N d ; B 28 -14 452 718 ;
-C 101 ; WX 456 ; N e ; B 19 -14 433 546 ;
-C 102 ; WX 273 ; N f ; B 8 0 261 727 ; L l fl ; L i fi ;
-C 103 ; WX 501 ; N g ; B 33 -217 453 546 ;
-C 104 ; WX 501 ; N h ; B 53 0 448 718 ;
-C 105 ; WX 228 ; N i ; B 57 0 171 725 ; L j ij ;
-C 106 ; WX 228 ; N j ; B 2 -214 171 725 ;
-C 107 ; WX 456 ; N k ; B 57 0 461 718 ;
-C 108 ; WX 228 ; N l ; B 57 0 171 718 ; L periodcentered ldot ;
-C 109 ; WX 729 ; N m ; B 52 0 677 546 ;
-C 110 ; WX 501 ; N n ; B 53 0 448 546 ;
-C 111 ; WX 501 ; N o ; B 28 -14 474 546 ;
-C 112 ; WX 501 ; N p ; B 51 -207 474 546 ;
-C 113 ; WX 501 ; N q ; B 28 -207 453 546 ;
-C 114 ; WX 319 ; N r ; B 52 0 306 546 ;
-C 115 ; WX 456 ; N s ; B 25 -14 426 546 ;
-C 116 ; WX 273 ; N t ; B 8 -6 253 676 ;
-C 117 ; WX 501 ; N u ; B 54 -14 447 532 ;
-C 118 ; WX 456 ; N v ; B 11 0 445 532 ;
-C 119 ; WX 638 ; N w ; B 8 0 631 532 ;
-C 120 ; WX 456 ; N x ; B 12 0 444 532 ;
-C 121 ; WX 456 ; N y ; B 8 -214 442 532 ;
-C 122 ; WX 410 ; N z ; B 16 0 394 532 ;
-C 123 ; WX 319 ; N braceleft ; B 39 -196 299 722 ;
-C 124 ; WX 230 ; N bar ; B 69 -19 161 737 ;
-C 125 ; WX 319 ; N braceright ; B 20 -196 280 722 ;
-C 126 ; WX 479 ; N asciitilde ; B 50 173 429 336 ;
-C 161 ; WX 273 ; N exclamdown ; B 74 -186 200 532 ;
-C 162 ; WX 456 ; N cent ; B 28 -118 430 628 ;
-C 163 ; WX 456 ; N sterling ; B 23 -16 444 718 ;
-C 164 ; WX 137 ; N fraction ; B -139 -19 276 710 ;
-C 165 ; WX 456 ; N yen ; B -7 0 463 698 ;
-C 166 ; WX 456 ; N florin ; B -8 -210 423 737 ;
-C 167 ; WX 456 ; N section ; B 28 -184 428 727 ;
-C 168 ; WX 456 ; N currency ; B -2 76 458 636 ;
-C 169 ; WX 195 ; N quotesingle ; B 57 447 138 718 ;
-C 170 ; WX 410 ; N quotedblleft ; B 52 454 358 727 ;
-C 171 ; WX 456 ; N guillemotleft ; B 72 76 384 484 ;
-C 172 ; WX 273 ; N guilsinglleft ; B 68 76 205 484 ;
-C 173 ; WX 273 ; N guilsinglright ; B 68 76 205 484 ;
-C 174 ; WX 501 ; N fi ; B 8 0 444 727 ;
-C 175 ; WX 501 ; N fl ; B 8 0 444 727 ;
-C 177 ; WX 456 ; N endash ; B 0 226 456 333 ;
-C 178 ; WX 456 ; N dagger ; B 30 -171 426 718 ;
-C 179 ; WX 456 ; N daggerdbl ; B 30 -171 426 718 ;
-C 180 ; WX 228 ; N periodcentered ; B 48 172 180 334 ;
-C 182 ; WX 456 ; N paragraph ; B -7 -191 442 700 ;
-C 183 ; WX 287 ; N bullet ; B 8 194 279 524 ;
-C 184 ; WX 228 ; N quotesinglbase ; B 57 -146 171 127 ;
-C 185 ; WX 410 ; N quotedblbase ; B 52 -146 358 127 ;
-C 186 ; WX 410 ; N quotedblright ; B 52 445 358 718 ;
-C 187 ; WX 456 ; N guillemotright ; B 72 76 384 484 ;
-C 188 ; WX 820 ; N ellipsis ; B 75 0 745 147 ;
-C 189 ; WX 820 ; N perthousand ; B -2 -19 822 710 ;
-C 191 ; WX 501 ; N questiondown ; B 45 -195 452 532 ;
-C 193 ; WX 273 ; N grave ; B -19 604 184 750 ;
-C 194 ; WX 273 ; N acute ; B 89 604 292 750 ;
-C 195 ; WX 273 ; N circumflex ; B -8 604 281 750 ;
-C 196 ; WX 273 ; N tilde ; B -14 610 287 737 ;
-C 197 ; WX 273 ; N macron ; B -5 605 278 678 ;
-C 198 ; WX 273 ; N breve ; B -2 604 275 750 ;
-C 199 ; WX 273 ; N dotaccent ; B 85 614 189 729 ;
-C 200 ; WX 273 ; N dieresis ; B 5 614 268 729 ;
-C 202 ; WX 273 ; N ring ; B 48 568 225 776 ;
-C 203 ; WX 273 ; N cedilla ; B 5 -228 201 0 ;
-C 205 ; WX 273 ; N hungarumlaut ; B 7 604 399 750 ;
-C 206 ; WX 273 ; N ogonek ; B 58 -228 249 0 ;
-C 207 ; WX 273 ; N caron ; B -8 604 281 750 ;
-C 208 ; WX 820 ; N emdash ; B 0 226 820 333 ;
-C 225 ; WX 820 ; N AE ; B 4 0 782 718 ;
-C 227 ; WX 303 ; N ordfeminine ; B 18 276 285 737 ;
-C 232 ; WX 501 ; N Lslash ; B -16 0 478 718 ;
-C 233 ; WX 638 ; N Oslash ; B 27 -27 610 745 ;
-C 234 ; WX 820 ; N OE ; B 30 -19 788 737 ;
-C 235 ; WX 299 ; N ordmasculine ; B 5 276 295 737 ;
-C 241 ; WX 729 ; N ae ; B 24 -14 704 546 ;
-C 245 ; WX 228 ; N dotlessi ; B 57 0 171 532 ;
-C 248 ; WX 228 ; N lslash ; B -15 0 243 718 ;
-C 249 ; WX 501 ; N oslash ; B 18 -29 483 560 ;
-C 250 ; WX 774 ; N oe ; B 28 -14 748 546 ;
-C 251 ; WX 501 ; N germandbls ; B 57 -14 475 731 ;
-C 255 ; WX 1000 ; N .notdef ; B 0 0 0 0 ;
-C -1 ; WX 592 ; N Adieresis ; B 16 0 576 915 ;
-C -1 ; WX 592 ; N Aacute ; B 16 0 576 936 ;
-C -1 ; WX 592 ; N Agrave ; B 16 0 576 936 ;
-C -1 ; WX 592 ; N Acircumflex ; B 16 0 576 936 ;
-C -1 ; WX 592 ; N Abreve ; B 16 0 576 936 ;
-C -1 ; WX 592 ; N Atilde ; B 16 0 576 923 ;
-C -1 ; WX 592 ; N Aring ; B 16 0 576 975 ;
-C -1 ; WX 592 ; N Aogonek ; B 16 -228 609 718 ;
-C -1 ; WX 592 ; N Ccedilla ; B 36 -228 561 737 ;
-C -1 ; WX 592 ; N Cacute ; B 36 -19 561 936 ;
-C -1 ; WX 592 ; N Ccaron ; B 36 -19 561 936 ;
-C -1 ; WX 592 ; N Dcaron ; B 62 0 562 936 ;
-C -1 ; WX 547 ; N Edieresis ; B 62 0 509 915 ;
-C -1 ; WX 547 ; N Eacute ; B 62 0 509 936 ;
-C -1 ; WX 547 ; N Egrave ; B 62 0 509 936 ;
-C -1 ; WX 547 ; N Ecircumflex ; B 62 0 509 936 ;
-C -1 ; WX 547 ; N Ecaron ; B 62 0 509 936 ;
-C -1 ; WX 547 ; N Edotaccent ; B 62 0 509 915 ;
-C -1 ; WX 547 ; N Eogonek ; B 62 -228 542 718 ;
-C -1 ; WX 638 ; N Gbreve ; B 36 -19 585 936 ;
-C -1 ; WX 228 ; N Idieresis ; B -17 0 246 915 ;
-C -1 ; WX 228 ; N Iacute ; B 52 0 270 936 ;
-C -1 ; WX 228 ; N Igrave ; B -41 0 175 936 ;
-C -1 ; WX 228 ; N Icircumflex ; B -30 0 259 936 ;
-C -1 ; WX 228 ; N Idotaccent ; B 52 0 175 915 ;
-C -1 ; WX 501 ; N Lacute ; B 62 0 478 936 ;
-C -1 ; WX 501 ; N Lcaron ; B 62 0 478 718 ;
-C -1 ; WX 592 ; N Nacute ; B 57 0 536 936 ;
-C -1 ; WX 592 ; N Ncaron ; B 57 0 536 936 ;
-C -1 ; WX 592 ; N Ntilde ; B 57 0 536 923 ;
-C -1 ; WX 638 ; N Odieresis ; B 36 -19 602 915 ;
-C -1 ; WX 638 ; N Oacute ; B 36 -19 602 936 ;
-C -1 ; WX 638 ; N Ograve ; B 36 -19 602 936 ;
-C -1 ; WX 638 ; N Ocircumflex ; B 36 -19 602 936 ;
-C -1 ; WX 638 ; N Otilde ; B 36 -19 602 923 ;
-C -1 ; WX 638 ; N Ohungarumlaut ; B 36 -19 602 936 ;
-C -1 ; WX 592 ; N Racute ; B 62 0 555 936 ;
-C -1 ; WX 592 ; N Rcaron ; B 62 0 555 936 ;
-C -1 ; WX 547 ; N Sacute ; B 32 -19 516 936 ;
-C -1 ; WX 547 ; N Scaron ; B 32 -19 516 936 ;
-C -1 ; WX 547 ; N Scedilla ; B 32 -228 516 737 ;
-C -1 ; WX 501 ; N Tcaron ; B 11 0 490 936 ;
-C -1 ; WX 592 ; N Udieresis ; B 59 -19 534 915 ;
-C -1 ; WX 592 ; N Uacute ; B 59 -19 534 936 ;
-C -1 ; WX 592 ; N Ugrave ; B 59 -19 534 936 ;
-C -1 ; WX 592 ; N Ucircumflex ; B 59 -19 534 936 ;
-C -1 ; WX 592 ; N Uring ; B 59 -19 534 962 ;
-C -1 ; WX 592 ; N Uhungarumlaut ; B 59 -19 559 936 ;
-C -1 ; WX 547 ; N Yacute ; B 12 0 535 936 ;
-C -1 ; WX 501 ; N Zacute ; B 20 0 481 936 ;
-C -1 ; WX 501 ; N Zcaron ; B 20 0 481 936 ;
-C -1 ; WX 501 ; N Zdotaccent ; B 20 0 481 915 ;
-C -1 ; WX 592 ; N Amacron ; B 16 0 576 864 ;
-C -1 ; WX 501 ; N Tcommaaccent ; B 11 -307 490 718 ;
-C -1 ; WX 547 ; N Ydieresis ; B 12 0 535 915 ;
-C -1 ; WX 547 ; N Emacron ; B 62 0 509 864 ;
-C -1 ; WX 228 ; N Imacron ; B -28 0 255 864 ;
-C -1 ; WX 228 ; N Iogonek ; B 17 -228 208 718 ;
-C -1 ; WX 592 ; N Kcommaaccent ; B 71 -307 592 718 ;
-C -1 ; WX 501 ; N Lcommaaccent ; B 62 -307 478 718 ;
-C -1 ; WX 592 ; N Ncommaaccent ; B 57 -307 536 718 ;
-C -1 ; WX 638 ; N Omacron ; B 36 -19 602 864 ;
-C -1 ; WX 592 ; N Rcommaaccent ; B 62 -307 555 718 ;
-C -1 ; WX 638 ; N Gcommaaccent ; B 36 -307 585 737 ;
-C -1 ; WX 592 ; N Umacron ; B 59 -19 534 864 ;
-C -1 ; WX 592 ; N Uogonek ; B 59 -228 534 718 ;
-C -1 ; WX 456 ; N adieresis ; B 24 -14 432 729 ;
-C -1 ; WX 456 ; N aacute ; B 24 -14 432 750 ;
-C -1 ; WX 456 ; N agrave ; B 24 -14 432 750 ;
-C -1 ; WX 456 ; N acircumflex ; B 24 -14 432 750 ;
-C -1 ; WX 456 ; N abreve ; B 24 -14 432 750 ;
-C -1 ; WX 456 ; N atilde ; B 24 -14 432 737 ;
-C -1 ; WX 456 ; N aring ; B 24 -14 432 803 ;
-C -1 ; WX 456 ; N aogonek ; B 24 -228 465 546 ;
-C -1 ; WX 456 ; N cacute ; B 28 -14 430 750 ;
-C -1 ; WX 456 ; N ccaron ; B 28 -14 430 750 ;
-C -1 ; WX 456 ; N ccedilla ; B 28 -228 430 546 ;
-C -1 ; WX 561 ; N dcaron ; B 28 -14 581 718 ;
-C -1 ; WX 456 ; N edieresis ; B 19 -14 433 729 ;
-C -1 ; WX 456 ; N eacute ; B 19 -14 433 750 ;
-C -1 ; WX 456 ; N egrave ; B 19 -14 433 750 ;
-C -1 ; WX 456 ; N ecircumflex ; B 19 -14 433 750 ;
-C -1 ; WX 456 ; N ecaron ; B 19 -14 433 750 ;
-C -1 ; WX 456 ; N edotaccent ; B 19 -14 433 729 ;
-C -1 ; WX 456 ; N eogonek ; B 19 -228 433 546 ;
-C -1 ; WX 501 ; N gbreve ; B 33 -217 453 750 ;
-C -1 ; WX 228 ; N idieresis ; B -17 0 246 729 ;
-C -1 ; WX 228 ; N iacute ; B 57 0 270 750 ;
-C -1 ; WX 228 ; N igrave ; B -41 0 171 750 ;
-C -1 ; WX 228 ; N icircumflex ; B -30 0 259 750 ;
-C -1 ; WX 228 ; N lacute ; B 57 0 270 936 ;
-C -1 ; WX 280 ; N lcaron ; B 57 0 300 718 ;
-C -1 ; WX 501 ; N nacute ; B 53 0 448 750 ;
-C -1 ; WX 501 ; N ncaron ; B 53 0 448 750 ;
-C -1 ; WX 501 ; N ntilde ; B 53 0 448 737 ;
-C -1 ; WX 501 ; N odieresis ; B 28 -14 474 729 ;
-C -1 ; WX 501 ; N oacute ; B 28 -14 474 750 ;
-C -1 ; WX 501 ; N ograve ; B 28 -14 474 750 ;
-C -1 ; WX 501 ; N ocircumflex ; B 28 -14 474 750 ;
-C -1 ; WX 501 ; N otilde ; B 28 -14 474 737 ;
-C -1 ; WX 501 ; N ohungarumlaut ; B 28 -14 513 750 ;
-C -1 ; WX 319 ; N racute ; B 52 0 315 750 ;
-C -1 ; WX 456 ; N sacute ; B 25 -14 426 750 ;
-C -1 ; WX 456 ; N scaron ; B 25 -14 426 750 ;
-C -1 ; WX 456 ; N scommaaccent ; B 25 -307 426 546 ;
-C -1 ; WX 338 ; N tcaron ; B 8 -6 358 718 ;
-C -1 ; WX 501 ; N udieresis ; B 54 -14 447 729 ;
-C -1 ; WX 501 ; N uacute ; B 54 -14 447 750 ;
-C -1 ; WX 501 ; N ugrave ; B 54 -14 447 750 ;
-C -1 ; WX 501 ; N ucircumflex ; B 54 -14 447 750 ;
-C -1 ; WX 501 ; N uring ; B 54 -14 447 776 ;
-C -1 ; WX 501 ; N uhungarumlaut ; B 54 -14 513 750 ;
-C -1 ; WX 456 ; N yacute ; B 8 -214 442 750 ;
-C -1 ; WX 410 ; N zacute ; B 16 0 394 750 ;
-C -1 ; WX 410 ; N zcaron ; B 16 0 394 750 ;
-C -1 ; WX 410 ; N zdotaccent ; B 16 0 394 729 ;
-C -1 ; WX 456 ; N ydieresis ; B 8 -214 442 729 ;
-C -1 ; WX 273 ; N tcommaaccent ; B 8 -307 253 676 ;
-C -1 ; WX 456 ; N amacron ; B 24 -14 432 678 ;
-C -1 ; WX 456 ; N emacron ; B 19 -14 433 678 ;
-C -1 ; WX 228 ; N imacron ; B -28 0 255 678 ;
-C -1 ; WX 456 ; N kcommaaccent ; B 57 -307 461 718 ;
-C -1 ; WX 228 ; N lcommaaccent ; B 57 -307 171 718 ;
-C -1 ; WX 501 ; N ncommaaccent ; B 53 -307 448 546 ;
-C -1 ; WX 501 ; N omacron ; B 28 -14 474 678 ;
-C -1 ; WX 319 ; N rcommaaccent ; B 52 -307 306 546 ;
-C -1 ; WX 501 ; N umacron ; B 54 -14 447 678 ;
-C -1 ; WX 501 ; N uogonek ; B 54 -228 480 532 ;
-C -1 ; WX 319 ; N rcaron ; B 30 0 319 750 ;
-C -1 ; WX 456 ; N scedilla ; B 25 -228 426 546 ;
-C -1 ; WX 501 ; N gcommaaccent ; B 33 -217 453 853 ;
-C -1 ; WX 228 ; N iogonek ; B 13 -228 204 725 ;
-C -1 ; WX 547 ; N Scommaaccent ; B 32 -307 516 737 ;
-C -1 ; WX 592 ; N Eth ; B -4 0 562 718 ;
-C -1 ; WX 592 ; N Dcroat ; B -4 0 562 718 ;
-C -1 ; WX 547 ; N Thorn ; B 62 0 514 718 ;
-C -1 ; WX 501 ; N dcroat ; B 28 -14 501 718 ;
-C -1 ; WX 501 ; N eth ; B 28 -14 474 737 ;
-C -1 ; WX 501 ; N thorn ; B 51 -207 474 718 ;
-C -1 ; WX 440 ; N Euro ; B 0 -12 433 678 ;
-C -1 ; WX 273 ; N onesuperior ; B 21 283 194 710 ;
-C -1 ; WX 273 ; N twosuperior ; B 7 283 266 722 ;
-C -1 ; WX 273 ; N threesuperior ; B 7 271 267 722 ;
-C -1 ; WX 328 ; N degree ; B 47 426 281 712 ;
-C -1 ; WX 479 ; N minus ; B 33 197 446 309 ;
-C -1 ; WX 479 ; N multiply ; B 33 1 447 505 ;
-C -1 ; WX 479 ; N divide ; B 33 -42 446 548 ;
-C -1 ; WX 820 ; N trademark ; B 36 306 784 718 ;
-C -1 ; WX 479 ; N plusminus ; B 33 0 446 578 ;
-C -1 ; WX 684 ; N onehalf ; B 21 -19 651 710 ;
-C -1 ; WX 684 ; N onequarter ; B 21 -19 628 710 ;
-C -1 ; WX 684 ; N threequarters ; B 13 -19 655 722 ;
-C -1 ; WX 273 ; N commaaccent ; B 83 -307 191 -60 ;
-C -1 ; WX 604 ; N copyright ; B -9 -19 614 737 ;
-C -1 ; WX 604 ; N registered ; B -9 -19 613 737 ;
-C -1 ; WX 405 ; N lozenge ; B 15 0 382 740 ;
-C -1 ; WX 502 ; N Delta ; B 5 0 499 688 ;
-C -1 ; WX 479 ; N notequal ; B 33 -16 446 522 ;
-C -1 ; WX 450 ; N radical ; B -27 -35 448 918 ;
-C -1 ; WX 479 ; N lessequal ; B 31 0 448 672 ;
-C -1 ; WX 479 ; N greaterequal ; B 31 0 448 672 ;
-C -1 ; WX 479 ; N logicalnot ; B 33 108 446 419 ;
-C -1 ; WX 585 ; N summation ; B 12 -123 570 752 ;
-C -1 ; WX 405 ; N partialdiff ; B 12 -21 388 743 ;
-C -1 ; WX 230 ; N brokenbar ; B 69 -19 161 737 ;
-C -1 ; WX 501 ; N mu ; B 54 -207 447 532 ;
-C -1 ; WX 592 ; N afii10017 ; B 16 0 576 718 ;
-C -1 ; WX 592 ; N afii10018 ; B 62 0 549 718 ;
-C -1 ; WX 592 ; N afii10019 ; B 62 0 549 718 ;
-C -1 ; WX 501 ; N afii10020 ; B 62 0 481 718 ;
-C -1 ; WX 712 ; N afii10021 ; B 25 -120 687 718 ;
-C -1 ; WX 547 ; N afii10022 ; B 62 0 509 718 ;
-C -1 ; WX 547 ; N afii10023 ; B 62 0 509 915 ;
-C -1 ; WX 878 ; N afii10024 ; B 0 0 878 718 ;
-C -1 ; WX 547 ; N afii10025 ; B 32 -19 516 737 ;
-C -1 ; WX 592 ; N afii10026 ; B 57 0 536 718 ;
-C -1 ; WX 592 ; N afii10027 ; B 57 0 536 912 ;
-C -1 ; WX 592 ; N afii10028 ; B 71 0 592 718 ;
-C -1 ; WX 592 ; N afii10029 ; B 15 0 541 718 ;
-C -1 ; WX 683 ; N afii10030 ; B 57 0 627 718 ;
-C -1 ; WX 592 ; N afii10031 ; B 58 0 534 718 ;
-C -1 ; WX 638 ; N afii10032 ; B 36 -19 602 737 ;
-C -1 ; WX 592 ; N afii10033 ; B 58 0 534 718 ;
-C -1 ; WX 547 ; N afii10034 ; B 62 0 514 718 ;
-C -1 ; WX 592 ; N afii10035 ; B 36 -19 561 737 ;
-C -1 ; WX 501 ; N afii10036 ; B 11 0 490 718 ;
-C -1 ; WX 547 ; N afii10037 ; B 12 0 535 718 ;
-C -1 ; WX 816 ; N afii10038 ; B 30 0 786 718 ;
-C -1 ; WX 547 ; N afii10039 ; B 11 0 535 718 ;
-C -1 ; WX 676 ; N afii10040 ; B 58 -120 651 718 ;
-C -1 ; WX 562 ; N afii10041 ; B 50 0 504 718 ;
-C -1 ; WX 741 ; N afii10042 ; B 58 0 683 718 ;
-C -1 ; WX 825 ; N afii10043 ; B 58 -120 800 718 ;
-C -1 ; WX 713 ; N afii10044 ; B 10 0 680 718 ;
-C -1 ; WX 728 ; N afii10045 ; B 62 0 670 718 ;
-C -1 ; WX 547 ; N afii10046 ; B 62 0 514 718 ;
-C -1 ; WX 592 ; N afii10047 ; B 36 -19 561 737 ;
-C -1 ; WX 914 ; N afii10048 ; B 58 -19 878 737 ;
-C -1 ; WX 570 ; N afii10049 ; B 30 0 512 718 ;
-C -1 ; WX 456 ; N afii10065 ; B 24 -14 432 546 ;
-C -1 ; WX 501 ; N afii10066 ; B 27 -14 483 776 ;
-C -1 ; WX 478 ; N afii10067 ; B 54 0 468 532 ;
-C -1 ; WX 384 ; N afii10068 ; B 53 0 371 532 ;
-C -1 ; WX 637 ; N afii10069 ; B 30 -120 607 532 ;
-C -1 ; WX 456 ; N afii10070 ; B 19 -14 433 546 ;
-C -1 ; WX 456 ; N afii10071 ; B 19 -14 433 729 ;
-C -1 ; WX 684 ; N afii10072 ; B -5 0 689 532 ;
-C -1 ; WX 456 ; N afii10073 ; B 25 -14 426 546 ;
-C -1 ; WX 496 ; N afii10074 ; B 53 0 448 532 ;
-C -1 ; WX 496 ; N afii10075 ; B 53 0 448 750 ;
-C -1 ; WX 456 ; N afii10076 ; B 57 0 461 532 ;
-C -1 ; WX 496 ; N afii10077 ; B 17 0 448 532 ;
-C -1 ; WX 646 ; N afii10078 ; B 53 0 593 532 ;
-C -1 ; WX 496 ; N afii10079 ; B 53 0 448 532 ;
-C -1 ; WX 501 ; N afii10080 ; B 28 -14 474 546 ;
-C -1 ; WX 501 ; N afii10081 ; B 53 0 448 532 ;
-C -1 ; WX 501 ; N afii10082 ; B 51 -207 474 546 ;
-C -1 ; WX 456 ; N afii10083 ; B 28 -14 430 546 ;
-C -1 ; WX 368 ; N afii10084 ; B 8 0 360 532 ;
-C -1 ; WX 456 ; N afii10085 ; B 8 -214 442 532 ;
-C -1 ; WX 786 ; N afii10086 ; B 27 -207 759 637 ;
-C -1 ; WX 456 ; N afii10087 ; B 12 0 444 532 ;
-C -1 ; WX 576 ; N afii10088 ; B 53 -120 562 532 ;
-C -1 ; WX 451 ; N afii10089 ; B 35 0 403 532 ;
-C -1 ; WX 676 ; N afii10090 ; B 53 0 623 532 ;
-C -1 ; WX 747 ; N afii10091 ; B 53 -120 737 532 ;
-C -1 ; WX 562 ; N afii10092 ; B 10 0 553 532 ;
-C -1 ; WX 682 ; N afii10093 ; B 54 0 633 532 ;
-C -1 ; WX 478 ; N afii10094 ; B 54 0 468 532 ;
-C -1 ; WX 456 ; N afii10095 ; B 28 -14 430 546 ;
-C -1 ; WX 722 ; N afii10096 ; B 53 -14 695 546 ;
-C -1 ; WX 478 ; N afii10097 ; B 10 0 424 532 ;
-C -1 ; WX 547 ; N uni0400 ; B 62 0 509 964 ;
-C -1 ; WX 651 ; N afii10051 ; B 11 -176 603 718 ;
-C -1 ; WX 501 ; N afii10052 ; B 62 0 481 920 ;
-C -1 ; WX 592 ; N afii10053 ; B 36 -19 561 737 ;
-C -1 ; WX 547 ; N afii10054 ; B 32 -19 516 737 ;
-C -1 ; WX 228 ; N afii10055 ; B 52 0 175 718 ;
-C -1 ; WX 228 ; N afii10056 ; B -17 0 246 915 ;
-C -1 ; WX 456 ; N afii10057 ; B 18 -18 397 718 ;
-C -1 ; WX 901 ; N afii10058 ; B 15 0 868 718 ;
-C -1 ; WX 896 ; N afii10059 ; B 58 0 863 718 ;
-C -1 ; WX 651 ; N afii10060 ; B 11 0 603 718 ;
-C -1 ; WX 592 ; N afii10061 ; B 71 0 592 920 ;
-C -1 ; WX 592 ; N uni040D ; B 57 0 536 964 ;
-C -1 ; WX 547 ; N afii10062 ; B 12 0 535 912 ;
-C -1 ; WX 543 ; N afii10145 ; B 30 -147 514 714 ;
-C -1 ; WX 456 ; N uni0450 ; B 19 -14 433 778 ;
-C -1 ; WX 511 ; N afii10099 ; B 2 -179 458 718 ;
-C -1 ; WX 384 ; N afii10100 ; B 53 0 373 770 ;
-C -1 ; WX 456 ; N afii10101 ; B 28 -14 430 546 ;
-C -1 ; WX 456 ; N afii10102 ; B 25 -14 426 546 ;
-C -1 ; WX 228 ; N afii10103 ; B 57 0 171 725 ;
-C -1 ; WX 228 ; N afii10104 ; B -17 0 246 729 ;
-C -1 ; WX 228 ; N afii10105 ; B 2 -214 171 725 ;
-C -1 ; WX 764 ; N afii10106 ; B 17 0 748 532 ;
-C -1 ; WX 758 ; N afii10107 ; B 53 0 748 532 ;
-C -1 ; WX 511 ; N afii10108 ; B 2 0 458 718 ;
-C -1 ; WX 456 ; N afii10109 ; B 57 0 461 770 ;
-C -1 ; WX 496 ; N uni045D ; B 53 0 448 778 ;
-C -1 ; WX 456 ; N afii10110 ; B 8 -214 442 750 ;
-C -1 ; WX 454 ; N afii10193 ; B 28 -122 425 532 ;
-C -1 ; WX 547 ; N uni048C ; B -5 0 514 718 ;
-C -1 ; WX 478 ; N uni048D ; B -5 0 468 532 ;
-C -1 ; WX 578 ; N uni048E ; B 62 0 554 718 ;
-C -1 ; WX 531 ; N uni048F ; B 51 -207 529 546 ;
-C -1 ; WX 501 ; N afii10050 ; B 62 0 481 822 ;
-C -1 ; WX 384 ; N afii10098 ; B 53 0 371 640 ;
-C -1 ; WX 501 ; N uni0492 ; B 0 0 481 718 ;
-C -1 ; WX 384 ; N uni0493 ; B 0 0 371 532 ;
-C -1 ; WX 571 ; N uni0494 ; B 62 -176 517 718 ;
-C -1 ; WX 500 ; N uni0495 ; B 53 -179 447 532 ;
-C -1 ; WX 878 ; N uni0496 ; B 0 -120 878 718 ;
-C -1 ; WX 684 ; N uni0497 ; B -5 -120 689 532 ;
-C -1 ; WX 547 ; N uni0498 ; B 32 -228 516 737 ;
-C -1 ; WX 456 ; N uni0499 ; B 25 -228 426 546 ;
-C -1 ; WX 592 ; N uni049A ; B 71 -120 592 718 ;
-C -1 ; WX 456 ; N uni049B ; B 57 -120 461 532 ;
-C -1 ; WX 592 ; N uni049C ; B 71 0 592 718 ;
-C -1 ; WX 456 ; N uni049D ; B 57 0 461 532 ;
-C -1 ; WX 592 ; N uni049E ; B -2 0 592 718 ;
-C -1 ; WX 456 ; N uni049F ; B 9 0 461 532 ;
-C -1 ; WX 749 ; N uni04A0 ; B 10 0 749 718 ;
-C -1 ; WX 536 ; N uni04A1 ; B 10 0 541 532 ;
-C -1 ; WX 676 ; N uni04A2 ; B 58 -120 651 718 ;
-C -1 ; WX 576 ; N uni04A3 ; B 53 -120 562 532 ;
-C -1 ; WX 919 ; N uni04A6 ; B 58 -176 865 718 ;
-C -1 ; WX 777 ; N uni04A7 ; B 53 -179 728 532 ;
-C -1 ; WX 592 ; N uni04A8 ; B 36 -22 574 737 ;
-C -1 ; WX 456 ; N uni04A9 ; B 28 -18 432 546 ;
-C -1 ; WX 592 ; N uni04AA ; B 36 -228 561 737 ;
-C -1 ; WX 456 ; N uni04AB ; B 28 -228 430 546 ;
-C -1 ; WX 501 ; N uni04AC ; B 11 -120 490 718 ;
-C -1 ; WX 368 ; N uni04AD ; B 8 -120 360 532 ;
-C -1 ; WX 547 ; N uni04AE ; B 12 0 535 718 ;
-C -1 ; WX 547 ; N uni04AF ; B 32 -186 515 532 ;
-C -1 ; WX 547 ; N uni04B0 ; B 12 0 535 718 ;
-C -1 ; WX 547 ; N uni04B1 ; B 32 -186 515 532 ;
-C -1 ; WX 547 ; N uni04B2 ; B 11 -120 535 718 ;
-C -1 ; WX 456 ; N uni04B3 ; B 12 -120 444 532 ;
-C -1 ; WX 791 ; N uni04B4 ; B 11 -120 766 718 ;
-C -1 ; WX 630 ; N uni04B5 ; B 8 -120 616 532 ;
-C -1 ; WX 646 ; N uni04B6 ; B 50 -120 621 718 ;
-C -1 ; WX 531 ; N uni04B7 ; B 35 -120 517 532 ;
-C -1 ; WX 562 ; N uni04B8 ; B 50 0 504 718 ;
-C -1 ; WX 451 ; N uni04B9 ; B 35 0 403 532 ;
-C -1 ; WX 562 ; N uni04BA ; B 50 0 504 718 ;
-C -1 ; WX 451 ; N uni04BB ; B 35 0 403 532 ;
-C -1 ; WX 848 ; N uni04BC ; B 20 -19 812 737 ;
-C -1 ; WX 683 ; N uni04BD ; B 31 -14 620 546 ;
-C -1 ; WX 848 ; N uni04BE ; B 21 -228 812 737 ;
-C -1 ; WX 683 ; N uni04BF ; B 31 -228 620 546 ;
-C -1 ; WX 228 ; N uni04C0 ; B 52 0 175 718 ;
-C -1 ; WX 878 ; N uni04C1 ; B 0 0 878 964 ;
-C -1 ; WX 684 ; N uni04C2 ; B -5 0 689 778 ;
-C -1 ; WX 592 ; N uni04C3 ; B 71 -176 578 718 ;
-C -1 ; WX 456 ; N uni04C4 ; B 57 -179 456 532 ;
-C -1 ; WX 592 ; N uni04C7 ; B 58 -176 534 718 ;
-C -1 ; WX 496 ; N uni04C8 ; B 53 -179 448 532 ;
-C -1 ; WX 562 ; N uni04CB ; B 50 -120 504 718 ;
-C -1 ; WX 451 ; N uni04CC ; B 35 -120 403 532 ;
-C -1 ; WX 592 ; N uni04D0 ; B 16 0 576 964 ;
-C -1 ; WX 456 ; N uni04D1 ; B 24 -14 432 778 ;
-C -1 ; WX 592 ; N uni04D2 ; B 16 0 576 933 ;
-C -1 ; WX 456 ; N uni04D3 ; B 24 -14 432 747 ;
-C -1 ; WX 820 ; N uni04D4 ; B 4 0 782 718 ;
-C -1 ; WX 729 ; N uni04D5 ; B 24 -14 704 546 ;
-C -1 ; WX 547 ; N uni04D6 ; B 62 0 509 964 ;
-C -1 ; WX 456 ; N uni04D7 ; B 19 -14 433 778 ;
-C -1 ; WX 638 ; N uni04D8 ; B 36 -19 602 737 ;
-C -1 ; WX 456 ; N afii10846 ; B 19 -14 433 546 ;
-C -1 ; WX 638 ; N uni04DA ; B 36 -19 602 872 ;
-C -1 ; WX 456 ; N uni04DB ; B 19 -14 433 681 ;
-C -1 ; WX 878 ; N uni04DC ; B 0 0 878 933 ;
-C -1 ; WX 684 ; N uni04DD ; B -5 0 689 747 ;
-C -1 ; WX 547 ; N uni04DE ; B 32 -19 516 933 ;
-C -1 ; WX 456 ; N uni04DF ; B 25 -14 426 747 ;
-C -1 ; WX 547 ; N uni04E0 ; B 32 -19 517 718 ;
-C -1 ; WX 456 ; N uni04E1 ; B 25 -14 427 532 ;
-C -1 ; WX 592 ; N uni04E2 ; B 57 0 536 891 ;
-C -1 ; WX 496 ; N uni04E3 ; B 53 0 448 705 ;
-C -1 ; WX 592 ; N uni04E4 ; B 57 0 536 933 ;
-C -1 ; WX 496 ; N uni04E5 ; B 53 0 448 747 ;
-C -1 ; WX 638 ; N uni04E6 ; B 36 -19 602 933 ;
-C -1 ; WX 501 ; N uni04E7 ; B 28 -14 474 747 ;
-C -1 ; WX 638 ; N uni04E8 ; B 36 -19 602 737 ;
-C -1 ; WX 501 ; N uni04E9 ; B 28 -14 474 546 ;
-C -1 ; WX 638 ; N uni04EA ; B 36 -19 602 933 ;
-C -1 ; WX 501 ; N uni04EB ; B 28 -14 474 747 ;
-C -1 ; WX 592 ; N uni04EC ; B 36 -19 561 933 ;
-C -1 ; WX 456 ; N uni04ED ; B 28 -14 430 747 ;
-C -1 ; WX 547 ; N uni04EE ; B 12 0 535 891 ;
-C -1 ; WX 456 ; N uni04EF ; B 8 -214 442 705 ;
-C -1 ; WX 547 ; N uni04F0 ; B 12 0 535 933 ;
-C -1 ; WX 456 ; N uni04F1 ; B 8 -214 442 747 ;
-C -1 ; WX 547 ; N uni04F2 ; B 12 0 535 964 ;
-C -1 ; WX 456 ; N uni04F3 ; B 8 -214 442 778 ;
-C -1 ; WX 562 ; N uni04F4 ; B 50 0 504 912 ;
-C -1 ; WX 451 ; N uni04F5 ; B 35 0 403 721 ;
-C -1 ; WX 728 ; N uni04F8 ; B 62 0 670 933 ;
-C -1 ; WX 682 ; N uni04F9 ; B 54 0 633 747 ;
-C -1 ; WX 384 ; N uniF6C4 ; B 53 0 371 532 ;
-C -1 ; WX 501 ; N uniF6C5 ; B 28 -14 483 776 ;
-C -1 ; WX 637 ; N uniF6C6 ; B 30 -120 607 532 ;
-C -1 ; WX 501 ; N uniF6C7 ; B 53 0 448 532 ;
-C -1 ; WX 368 ; N uniF6C8 ; B 8 0 360 532 ;
-C -1 ; WX 592 ; N Ccircumflex ; B 36 -19 561 964 ;
-C -1 ; WX 456 ; N ccircumflex ; B 28 -14 433 778 ;
-C -1 ; WX 592 ; N Cdotaccent ; B 36 -19 561 933 ;
-C -1 ; WX 456 ; N cdotaccent ; B 28 -14 430 747 ;
-C -1 ; WX 547 ; N Ebreve ; B 62 0 509 964 ;
-C -1 ; WX 456 ; N ebreve ; B 19 -14 433 778 ;
-C -1 ; WX 638 ; N Gcircumflex ; B 36 -19 585 964 ;
-C -1 ; WX 501 ; N gcircumflex ; B 33 -217 453 778 ;
-C -1 ; WX 638 ; N Gdotaccent ; B 36 -19 585 933 ;
-C -1 ; WX 501 ; N gdotaccent ; B 33 -217 453 747 ;
-C -1 ; WX 592 ; N Hcircumflex ; B 58 0 534 964 ;
-C -1 ; WX 501 ; N hcircumflex ; B 53 0 448 964 ;
-C -1 ; WX 715 ; N Hbar ; B 36 0 679 718 ;
-C -1 ; WX 564 ; N hbar ; B 36 0 511 718 ;
-C -1 ; WX 228 ; N Itilde ; B -37 0 264 945 ;
-C -1 ; WX 228 ; N itilde ; B -36 0 265 759 ;
-C -1 ; WX 228 ; N Ibreve ; B -25 0 252 964 ;
-C -1 ; WX 228 ; N ibreve ; B -24 0 253 778 ;
-C -1 ; WX 648 ; N IJ ; B 52 -18 597 718 ;
-C -1 ; WX 398 ; N ij ; B 57 -214 345 725 ;
-C -1 ; WX 456 ; N Jcircumflex ; B 18 -18 480 964 ;
-C -1 ; WX 228 ; N jcircumflex ; B -8 -214 281 750 ;
-C -1 ; WX 456 ; N kgreenlandic ; B 57 0 461 532 ;
-C -1 ; WX 501 ; N Ldot ; B 62 0 478 718 ;
-C -1 ; WX 456 ; N ldot ; B 57 0 408 718 ;
-C -1 ; WX 501 ; N napostrophe ; B 53 0 448 818 ;
-C -1 ; WX 592 ; N Eng ; B 57 -176 536 718 ;
-C -1 ; WX 501 ; N eng ; B 53 -179 448 546 ;
-C -1 ; WX 638 ; N Obreve ; B 36 -19 602 964 ;
-C -1 ; WX 501 ; N obreve ; B 28 -14 474 778 ;
-C -1 ; WX 547 ; N Scircumflex ; B 32 -19 516 964 ;
-C -1 ; WX 456 ; N scircumflex ; B 25 -14 426 778 ;
-C -1 ; WX 501 ; N Tbar ; B 11 0 490 718 ;
-C -1 ; WX 273 ; N tbar ; B 8 -6 253 676 ;
-C -1 ; WX 592 ; N Utilde ; B 59 -19 534 945 ;
-C -1 ; WX 501 ; N utilde ; B 54 -14 447 759 ;
-C -1 ; WX 592 ; N Ubreve ; B 59 -19 534 964 ;
-C -1 ; WX 501 ; N ubreve ; B 54 -14 447 778 ;
-C -1 ; WX 774 ; N Wcircumflex ; B 13 0 762 964 ;
-C -1 ; WX 638 ; N wcircumflex ; B 8 0 631 778 ;
-C -1 ; WX 547 ; N Ycircumflex ; B 12 0 535 964 ;
-C -1 ; WX 456 ; N ycircumflex ; B 8 -214 442 778 ;
-C -1 ; WX 273 ; N longs ; B 8 0 259 727 ;
-C -1 ; WX 850 ; N afii61352 ; B 57 0 810 718 ;
-C -1 ; WX 702 ; N infinity ; B 25 162 677 529 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 969
-KPX quoteright A -55
-KPX quoteright AE -51
-KPX quoteright Aacute -55
-KPX quoteright Adieresis -55
-KPX quoteright Aring -55
-KPX quoteright comma -31
-KPX quoteright d -18
-KPX quoteright o -24
-KPX quoteright period -31
-KPX quoteright r -7
-KPX quoteright s -16
-KPX quoteright t 4
-KPX quoteright w 5
-KPX quoteright y 2
-KPX comma one -59
-KPX comma quotedblright -18
-KPX comma quoteright -20
-KPX hyphen A 7
-KPX hyphen AE 12
-KPX hyphen Aacute 7
-KPX hyphen Adieresis 7
-KPX hyphen Aring 7
-KPX hyphen T -39
-KPX hyphen V -14
-KPX hyphen W -3
-KPX hyphen Y -45
-KPX period one -59
-KPX period quotedblright -18
-KPX period quoteright -20
-KPX zero four 11
-KPX zero one -10
-KPX zero seven -1
-KPX one comma -32
-KPX one eight -32
-KPX one five -33
-KPX one four -46
-KPX one nine -32
-KPX one one -65
-KPX one period -32
-KPX one seven -47
-KPX one six -29
-KPX one three -36
-KPX one two -37
-KPX one zero -28
-KPX two four -11
-KPX two one -11
-KPX three four 8
-KPX three one -18
-KPX three seven -3
-KPX four four 12
-KPX four one -37
-KPX four seven -19
-KPX five four 8
-KPX five one -20
-KPX five seven -2
-KPX six four 10
-KPX six one -13
-KPX six seven 1
-KPX seven colon -40
-KPX seven comma -71
-KPX seven eight -2
-KPX seven five -9
-KPX seven four -53
-KPX seven one -4
-KPX seven period -71
-KPX seven seven 14
-KPX seven six -6
-KPX seven three 1
-KPX seven two 1
-KPX eight four 12
-KPX eight one -15
-KPX nine four 10
-KPX nine one -11
-KPX nine seven -4
-KPX A C -26
-KPX A Ccedilla -26
-KPX A G -27
-KPX A O -27
-KPX A Odieresis -27
-KPX A Q -27
-KPX A T -62
-KPX A U -24
-KPX A Uacute -24
-KPX A Ucircumflex -24
-KPX A Udieresis -24
-KPX A Ugrave -24
-KPX A V -50
-KPX A W -41
-KPX A Y -69
-KPX A a -1
-KPX A b -1
-KPX A c -11
-KPX A ccedilla -11
-KPX A comma 17
-KPX A d -11
-KPX A e -7
-KPX A g -16
-KPX A guillemotleft -35
-KPX A guilsinglleft -33
-KPX A hyphen 7
-KPX A o -14
-KPX A period 17
-KPX A q -12
-KPX A quotedblright -47
-KPX A quoteright -50
-KPX A t -12
-KPX A u -12
-KPX A v -29
-KPX A w -19
-KPX A y -27
-KPX B A -17
-KPX B AE -11
-KPX B Aacute -17
-KPX B Acircumflex -17
-KPX B Adieresis -17
-KPX B Aring -17
-KPX B Atilde -17
-KPX B O -4
-KPX B OE 1
-KPX B Oacute -4
-KPX B Ocircumflex -4
-KPX B Odieresis -4
-KPX B Ograve -4
-KPX B Oslash -1
-KPX B V -22
-KPX B W -17
-KPX B Y -29
-KPX C A -19
-KPX C AE -14
-KPX C Aacute -19
-KPX C Adieresis -19
-KPX C Aring -19
-KPX C H 1
-KPX C K -5
-KPX C O -2
-KPX C Oacute -2
-KPX C Odieresis -2
-KPX D A -24
-KPX D Aacute -24
-KPX D Acircumflex -24
-KPX D Adieresis -24
-KPX D Agrave -24
-KPX D Aring -24
-KPX D Atilde -24
-KPX D J 8
-KPX D T -3
-KPX D V -20
-KPX D W -13
-KPX D X -22
-KPX D Y -31
-KPX F A -43
-KPX F Aacute -43
-KPX F Acircumflex -43
-KPX F Adieresis -43
-KPX F Agrave -43
-KPX F Aring -43
-KPX F Atilde -43
-KPX F J -14
-KPX F O -10
-KPX F Odieresis -10
-KPX F a -15
-KPX F aacute -15
-KPX F adieresis -15
-KPX F ae -16
-KPX F aring -15
-KPX F comma -71
-KPX F e -6
-KPX F eacute -6
-KPX F hyphen 8
-KPX F i -6
-KPX F j -6
-KPX F o -11
-KPX F oacute -11
-KPX F odieresis -11
-KPX F oe -11
-KPX F oslash -11
-KPX F period -71
-KPX F r -22
-KPX F u -23
-KPX G A 1
-KPX G AE 7
-KPX G Aacute 1
-KPX G Acircumflex 1
-KPX G Adieresis 1
-KPX G Agrave 1
-KPX G Aring 1
-KPX G Atilde 1
-KPX G T -6
-KPX G V -24
-KPX G W -15
-KPX G Y -35
-KPX J A -21
-KPX J AE -15
-KPX J Adieresis -21
-KPX J Aring -21
-KPX K C -35
-KPX K G -36
-KPX K O -36
-KPX K OE -30
-KPX K Oacute -36
-KPX K Odieresis -36
-KPX K S -18
-KPX K T 23
-KPX K ae -1
-KPX K e -17
-KPX K hyphen -26
-KPX K o -25
-KPX K oacute -25
-KPX K odieresis -25
-KPX K u -19
-KPX K udieresis -19
-KPX K y -48
-KPX L A 16
-KPX L AE 22
-KPX L Aacute 16
-KPX L Adieresis 16
-KPX L Aring 16
-KPX L C -13
-KPX L Ccedilla -16
-KPX L G -15
-KPX L O -15
-KPX L Oacute -15
-KPX L Ocircumflex -15
-KPX L Odieresis -15
-KPX L Ograve -15
-KPX L Otilde -15
-KPX L S 3
-KPX L T -70
-KPX L U -12
-KPX L Udieresis -12
-KPX L V -64
-KPX L W -50
-KPX L Y -83
-KPX L hyphen -8
-KPX L quotedblright -115
-KPX L quoteright -118
-KPX L u -7
-KPX L udieresis -7
-KPX L y -41
-KPX N AE 6
-KPX N C 7
-KPX N Ccedilla 7
-KPX N G 6
-KPX N O 6
-KPX N Oacute 6
-KPX N Odieresis 6
-KPX N a 7
-KPX N aacute 7
-KPX N adieresis 7
-KPX N ae 6
-KPX N aring 7
-KPX N comma 12
-KPX N e 12
-KPX N eacute 12
-KPX N o 6
-KPX N oacute 6
-KPX N odieresis 6
-KPX N oslash 7
-KPX N period 12
-KPX N u 5
-KPX N udieresis 5
-KPX O A -28
-KPX O AE -22
-KPX O Aacute -28
-KPX O Adieresis -28
-KPX O Aring -28
-KPX O T -9
-KPX O V -26
-KPX O W -17
-KPX O X -26
-KPX O Y -38
-KPX P A -51
-KPX P AE -47
-KPX P Aacute -51
-KPX P Adieresis -51
-KPX P Aring -51
-KPX P J -36
-KPX P a -12
-KPX P aacute -12
-KPX P adieresis -12
-KPX P ae -13
-KPX P aring -12
-KPX P comma -92
-KPX P e -10
-KPX P eacute -10
-KPX P hyphen -3
-KPX P o -16
-KPX P oacute -16
-KPX P odieresis -16
-KPX P oe -16
-KPX P oslash -16
-KPX P period -92
-KPX R C -2
-KPX R Ccedilla -2
-KPX R G -3
-KPX R O -3
-KPX R OE 1
-KPX R Oacute -3
-KPX R Odieresis -3
-KPX R T 3
-KPX R U -1
-KPX R Udieresis -1
-KPX R V -16
-KPX R W -12
-KPX R Y -24
-KPX R ae -1
-KPX R e 2
-KPX R eacute 2
-KPX R hyphen 14
-KPX R o -4
-KPX R oacute -4
-KPX R odieresis -4
-KPX R oe -4
-KPX R u -1
-KPX R uacute -2
-KPX R udieresis -2
-KPX R y 3
-KPX S A -10
-KPX S AE -5
-KPX S Aacute -10
-KPX S Adieresis -10
-KPX S Aring -10
-KPX S V -20
-KPX S W -15
-KPX S Y -27
-KPX S t 2
-KPX T A -63
-KPX T AE -59
-KPX T Aacute -63
-KPX T Acircumflex -63
-KPX T Adieresis -63
-KPX T Agrave -63
-KPX T Aring -63
-KPX T Atilde -63
-KPX T C -8
-KPX T G -10
-KPX T J -67
-KPX T O -9
-KPX T OE -3
-KPX T Oacute -9
-KPX T Ocircumflex -9
-KPX T Odieresis -9
-KPX T Ograve -9
-KPX T Oslash -9
-KPX T Otilde -9
-KPX T S 6
-KPX T V 22
-KPX T W 23
-KPX T Y 23
-KPX T a -62
-KPX T ae -63
-KPX T c -62
-KPX T colon -73
-KPX T comma -55
-KPX T e -58
-KPX T g -65
-KPX T guillemotleft -84
-KPX T guilsinglleft -82
-KPX T hyphen -39
-KPX T i -2
-KPX T j -2
-KPX T o -65
-KPX T oslash -61
-KPX T period -55
-KPX T r -59
-KPX T s -63
-KPX T semicolon -73
-KPX T u -63
-KPX T v -68
-KPX T w -67
-KPX T y -67
-KPX U A -24
-KPX U AE -20
-KPX U Aacute -24
-KPX U Acircumflex -24
-KPX U Adieresis -24
-KPX U Aring -24
-KPX U Atilde -24
-KPX U comma -6
-KPX U m 4
-KPX U n 3
-KPX U p 4
-KPX U period -3
-KPX U r 4
-KPX V A -51
-KPX V AE -46
-KPX V Aacute -51
-KPX V Acircumflex -51
-KPX V Adieresis -51
-KPX V Agrave -51
-KPX V Aring -51
-KPX V Atilde -51
-KPX V C -25
-KPX V G -26
-KPX V O -26
-KPX V Oacute -26
-KPX V Ocircumflex -26
-KPX V Odieresis -26
-KPX V Ograve -26
-KPX V Oslash -22
-KPX V Otilde -26
-KPX V S -13
-KPX V T 22
-KPX V a -38
-KPX V ae -39
-KPX V colon -38
-KPX V comma -52
-KPX V e -34
-KPX V g -40
-KPX V guillemotleft -59
-KPX V guilsinglleft -57
-KPX V hyphen -14
-KPX V i -4
-KPX V o -40
-KPX V oslash -37
-KPX V period -52
-KPX V r -27
-KPX V semicolon -38
-KPX V u -31
-KPX V y -7
-KPX W A -40
-KPX W AE -36
-KPX W Aacute -40
-KPX W Acircumflex -40
-KPX W Adieresis -40
-KPX W Agrave -40
-KPX W Aring -40
-KPX W Atilde -40
-KPX W C -15
-KPX W G -16
-KPX W O -16
-KPX W Oacute -16
-KPX W Ocircumflex -16
-KPX W Odieresis -16
-KPX W Ograve -16
-KPX W Oslash -12
-KPX W Otilde -16
-KPX W S -8
-KPX W T 24
-KPX W a -26
-KPX W ae -27
-KPX W colon -31
-KPX W comma -36
-KPX W e -21
-KPX W g -27
-KPX W guillemotleft -47
-KPX W guilsinglleft -45
-KPX W hyphen -2
-KPX W i -2
-KPX W o -28
-KPX W oslash -25
-KPX W period -36
-KPX W r -21
-KPX W semicolon -31
-KPX W u -24
-KPX W y -1
-KPX X C -26
-KPX X O -27
-KPX X Odieresis -27
-KPX X Q -27
-KPX X a -5
-KPX X e -20
-KPX X hyphen -21
-KPX X o -27
-KPX X u -24
-KPX X y -35
-KPX Y A -67
-KPX Y AE -62
-KPX Y Aacute -67
-KPX Y Acircumflex -67
-KPX Y Adieresis -67
-KPX Y Agrave -67
-KPX Y Aring -67
-KPX Y Atilde -67
-KPX Y C -36
-KPX Y G -38
-KPX Y O -37
-KPX Y Oacute -37
-KPX Y Ocircumflex -37
-KPX Y Odieresis -37
-KPX Y Ograve -37
-KPX Y Oslash -37
-KPX Y Otilde -37
-KPX Y S -19
-KPX Y T 24
-KPX Y a -58
-KPX Y ae -59
-KPX Y colon -52
-KPX Y comma -65
-KPX Y e -54
-KPX Y g -61
-KPX Y guillemotleft -83
-KPX Y guilsinglleft -81
-KPX Y hyphen -42
-KPX Y i -2
-KPX Y o -61
-KPX Y oslash -57
-KPX Y p -39
-KPX Y period -65
-KPX Y semicolon -52
-KPX Y u -45
-KPX Y v -22
-KPX Z v -9
-KPX Z y -8
-KPX quoteleft A -51
-KPX quoteleft AE -47
-KPX quoteleft Aacute -51
-KPX quoteleft Adieresis -51
-KPX quoteleft Aring -51
-KPX quoteleft T 1
-KPX quoteleft V 7
-KPX quoteleft W 12
-KPX a quoteright -7
-KPX a v -15
-KPX a w -6
-KPX a y -13
-KPX b v -15
-KPX b w -5
-KPX b y -14
-KPX c k -2
-KPX e quoteright -8
-KPX e t -2
-KPX e v -15
-KPX e w -6
-KPX e x -16
-KPX e y -14
-KPX f a -5
-KPX f aacute -5
-KPX f adieresis -5
-KPX f ae -6
-KPX f aring -5
-KPX f e -5
-KPX f eacute -5
-KPX f f 17
-KPX f i -3
-KPX f j -7
-KPX f l -3
-KPX f o -12
-KPX f oacute -12
-KPX f odieresis -12
-KPX f oe -12
-KPX f oslash -9
-KPX f quoteright 11
-KPX f s -5
-KPX f t 17
-KPX g a 5
-KPX g adieresis 5
-KPX g ae 5
-KPX g aring 5
-KPX g e 10
-KPX g eacute 10
-KPX g l 3
-KPX g oacute 4
-KPX g odieresis 4
-KPX g r 6
-KPX h quoteright -7
-KPX h y -14
-KPX i T -2
-KPX i j -1
-KPX k comma 15
-KPX k e -6
-KPX k eacute -6
-KPX k g -14
-KPX k hyphen -10
-KPX k o -13
-KPX k oacute -13
-KPX k odieresis -13
-KPX k period 15
-KPX k s -8
-KPX k u -4
-KPX l v -7
-KPX l y -5
-KPX m p 3
-KPX m v -16
-KPX m w -7
-KPX m y -14
-KPX n T -63
-KPX n p 3
-KPX n quoteright -7
-KPX n v -16
-KPX n w -7
-KPX n y -14
-KPX o T -64
-KPX o quoteright -13
-KPX o t -5
-KPX o v -18
-KPX o w -8
-KPX o x -20
-KPX o y -17
-KPX p t -1
-KPX p y -14
-KPX q c 6
-KPX q u 4
-KPX r a -1
-KPX r aacute -1
-KPX r acircumflex -1
-KPX r adieresis -1
-KPX r ae -2
-KPX r agrave -1
-KPX r aring -1
-KPX r c -4
-KPX r ccedilla -1
-KPX r colon -12
-KPX r comma -42
-KPX r d -3
-KPX r f 17
-KPX r g -2
-KPX r h -5
-KPX r hyphen -24
-KPX r i -7
-KPX r j -7
-KPX r k -7
-KPX r l -7
-KPX r m -5
-KPX r n -5
-KPX r o -6
-KPX r oacute -6
-KPX r ocircumflex -6
-KPX r odieresis -6
-KPX r oe -6
-KPX r ograve -6
-KPX r oslash -6
-KPX r p -4
-KPX r period -42
-KPX r q -3
-KPX r quoteright 13
-KPX r r -5
-KPX r s -1
-KPX r semicolon -12
-KPX r t 17
-KPX r u -6
-KPX r v 15
-KPX r w 16
-KPX r x 10
-KPX r y 16
-KPX r z 5
-KPX s quoteright -11
-KPX s t -5
-KPX t S 1
-KPX t a 4
-KPX t aacute 4
-KPX t adieresis 4
-KPX t ae 4
-KPX t aring 4
-KPX t colon -5
-KPX t e -2
-KPX t eacute -2
-KPX t h 5
-KPX t o -8
-KPX t oacute -8
-KPX t odieresis -8
-KPX t quoteright 7
-KPX t semicolon -4
-KPX u quoteright 1
-KPX v a -17
-KPX v aacute -17
-KPX v acircumflex -17
-KPX v adieresis -17
-KPX v ae -18
-KPX v agrave -17
-KPX v aring -17
-KPX v atilde -17
-KPX v c -16
-KPX v colon -13
-KPX v comma -35
-KPX v e -12
-KPX v eacute -12
-KPX v ecircumflex -12
-KPX v egrave -12
-KPX v g -18
-KPX v hyphen 5
-KPX v l -7
-KPX v o -19
-KPX v oacute -19
-KPX v odieresis -19
-KPX v ograve -19
-KPX v oslash -16
-KPX v period -35
-KPX v s -17
-KPX v semicolon -13
-KPX w a -7
-KPX w aacute -7
-KPX w acircumflex -7
-KPX w adieresis -7
-KPX w ae -8
-KPX w agrave -7
-KPX w aring -7
-KPX w atilde -7
-KPX w c -7
-KPX w colon -10
-KPX w comma -20
-KPX w e -2
-KPX w eacute -2
-KPX w ecircumflex -2
-KPX w egrave -2
-KPX w g -8
-KPX w hyphen 14
-KPX w l -3
-KPX w o -9
-KPX w oacute -9
-KPX w odieresis -9
-KPX w ograve -9
-KPX w oslash -6
-KPX w period -20
-KPX w s -8
-KPX w semicolon -10
-KPX x a -10
-KPX x c -17
-KPX x e -13
-KPX x eacute -13
-KPX x o -20
-KPX x q -17
-KPX y a -18
-KPX y aacute -18
-KPX y acircumflex -18
-KPX y adieresis -18
-KPX y ae -19
-KPX y agrave -18
-KPX y aring -18
-KPX y atilde -18
-KPX y c -18
-KPX y colon -14
-KPX y comma -36
-KPX y e -14
-KPX y eacute -14
-KPX y ecircumflex -14
-KPX y egrave -14
-KPX y g -20
-KPX y hyphen 4
-KPX y l -8
-KPX y o -20
-KPX y oacute -20
-KPX y odieresis -20
-KPX y ograve -20
-KPX y oslash -17
-KPX y period -35
-KPX y s -19
-KPX y semicolon -14
-KPX quotedblleft A -49
-KPX quotedblleft AE -45
-KPX quotedblleft Aacute -49
-KPX quotedblleft Adieresis -49
-KPX quotedblleft Aring -49
-KPX quotedblleft T 3
-KPX quotedblleft V 10
-KPX quotedblleft W 15
-KPX quotedblleft Y 2
-KPX guilsinglright A -33
-KPX guilsinglright AE -28
-KPX guilsinglright Aacute -33
-KPX guilsinglright Adieresis -33
-KPX guilsinglright Aring -33
-KPX guilsinglright T -82
-KPX guilsinglright V -56
-KPX guilsinglright W -45
-KPX guilsinglright Y -84
-KPX quotedblbase A 16
-KPX quotedblbase AE 22
-KPX quotedblbase T -56
-KPX quotedblbase V -53
-KPX quotedblbase W -38
-KPX quotedblbase Y -69
-KPX quotedblright A -52
-KPX quotedblright AE -48
-KPX quotedblright Aacute -52
-KPX quotedblright Adieresis -52
-KPX quotedblright Aring -52
-KPX quotedblright T 4
-KPX quotedblright V 7
-KPX quotedblright W 12
-KPX guillemotright A -36
-KPX guillemotright AE -30
-KPX guillemotright Aacute -36
-KPX guillemotright Adieresis -36
-KPX guillemotright Aring -36
-KPX guillemotright T -84
-KPX guillemotright V -59
-KPX guillemotright W -48
-KPX guillemotright Y -86
-KPX Oslash A -24
-KPX ae v -16
-KPX ae w -6
-KPX ae y -15
-KPX Adieresis C -26
-KPX Adieresis G -27
-KPX Adieresis O -27
-KPX Adieresis Q -27
-KPX Adieresis T -62
-KPX Adieresis U -24
-KPX Adieresis V -50
-KPX Adieresis W -41
-KPX Adieresis Y -69
-KPX Adieresis a -1
-KPX Adieresis b -1
-KPX Adieresis c -11
-KPX Adieresis comma 17
-KPX Adieresis d -11
-KPX Adieresis g -16
-KPX Adieresis guillemotleft -35
-KPX Adieresis guilsinglleft -33
-KPX Adieresis hyphen 7
-KPX Adieresis o -14
-KPX Adieresis period 17
-KPX Adieresis q -12
-KPX Adieresis quotedblright -47
-KPX Adieresis quoteright -50
-KPX Adieresis t -12
-KPX Adieresis u -12
-KPX Adieresis v -29
-KPX Adieresis w -19
-KPX Adieresis y -27
-KPX Aacute C -26
-KPX Aacute G -27
-KPX Aacute O -27
-KPX Aacute Q -27
-KPX Aacute T -62
-KPX Aacute U -24
-KPX Aacute V -50
-KPX Aacute W -41
-KPX Aacute Y -69
-KPX Aacute a -1
-KPX Aacute b -1
-KPX Aacute c -11
-KPX Aacute comma 17
-KPX Aacute d -11
-KPX Aacute e -7
-KPX Aacute g -16
-KPX Aacute guillemotleft -35
-KPX Aacute guilsinglleft -33
-KPX Aacute hyphen 7
-KPX Aacute o -14
-KPX Aacute period 17
-KPX Aacute q -12
-KPX Aacute quoteright -50
-KPX Aacute t -12
-KPX Aacute u -12
-KPX Aacute v -29
-KPX Aacute w -19
-KPX Aacute y -27
-KPX Agrave C -26
-KPX Agrave G -27
-KPX Agrave O -27
-KPX Agrave Q -27
-KPX Agrave T -62
-KPX Agrave U -24
-KPX Agrave V -50
-KPX Agrave W -41
-KPX Agrave Y -69
-KPX Agrave comma 17
-KPX Agrave period 17
-KPX Acircumflex C -26
-KPX Acircumflex G -27
-KPX Acircumflex O -27
-KPX Acircumflex Q -27
-KPX Acircumflex T -62
-KPX Acircumflex U -24
-KPX Acircumflex V -50
-KPX Acircumflex W -41
-KPX Acircumflex Y -69
-KPX Acircumflex comma 17
-KPX Acircumflex period 17
-KPX Atilde C -26
-KPX Atilde G -27
-KPX Atilde O -27
-KPX Atilde Q -27
-KPX Atilde T -62
-KPX Atilde U -24
-KPX Atilde V -50
-KPX Atilde W -41
-KPX Atilde Y -69
-KPX Atilde comma 17
-KPX Atilde period 17
-KPX Aring C -26
-KPX Aring G -27
-KPX Aring O -27
-KPX Aring Q -27
-KPX Aring T -62
-KPX Aring U -24
-KPX Aring V -50
-KPX Aring W -41
-KPX Aring Y -69
-KPX Aring a -1
-KPX Aring b -1
-KPX Aring c -11
-KPX Aring comma 17
-KPX Aring d -11
-KPX Aring e -7
-KPX Aring g -16
-KPX Aring guillemotleft -35
-KPX Aring guilsinglleft -33
-KPX Aring hyphen 7
-KPX Aring o -14
-KPX Aring period 17
-KPX Aring q -12
-KPX Aring quotedblright -47
-KPX Aring quoteright -50
-KPX Aring t -12
-KPX Aring u -12
-KPX Aring v -29
-KPX Aring w -19
-KPX Aring y -27
-KPX Ccedilla A -21
-KPX Odieresis A -28
-KPX Odieresis T -9
-KPX Odieresis V -26
-KPX Odieresis W -17
-KPX Odieresis X -26
-KPX Odieresis Y -38
-KPX Oacute A -28
-KPX Oacute T -9
-KPX Oacute V -26
-KPX Oacute W -17
-KPX Oacute Y -38
-KPX Ograve T -9
-KPX Ograve V -26
-KPX Ograve Y -38
-KPX Ocircumflex T -9
-KPX Ocircumflex V -26
-KPX Ocircumflex Y -38
-KPX Otilde T -9
-KPX Otilde V -26
-KPX Otilde Y -38
-KPX Udieresis A -24
-KPX Udieresis b 4
-KPX Udieresis comma -6
-KPX Udieresis m 4
-KPX Udieresis n 3
-KPX Udieresis p 4
-KPX Udieresis period -3
-KPX Udieresis r 4
-KPX Uacute A -24
-KPX Uacute comma -6
-KPX Uacute m 4
-KPX Uacute n 3
-KPX Uacute p 4
-KPX Uacute period -3
-KPX Uacute r 4
-KPX Ugrave A -24
-KPX Ucircumflex A -24
-KPX adieresis v -15
-KPX adieresis w -6
-KPX adieresis y -13
-KPX aacute v -15
-KPX aacute w -6
-KPX aacute y -13
-KPX agrave v -15
-KPX agrave w -6
-KPX agrave y -13
-KPX aring v -15
-KPX aring w -6
-KPX aring y -13
-KPX eacute v -15
-KPX eacute w -6
-KPX eacute y -14
-KPX ecircumflex v -15
-KPX ecircumflex w -6
-KPX ecircumflex y -14
-KPX odieresis t -5
-KPX odieresis v -18
-KPX odieresis w -8
-KPX odieresis x -20
-KPX odieresis y -17
-KPX oacute v -18
-KPX oacute w -8
-KPX oacute y -17
-KPX ograve v -18
-KPX ograve w -8
-KPX ograve y -17
-KPX ocircumflex t -5
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-sans-l/n019044l.pfb b/src/fonts/nimbus-sans-l/n019044l.pfb
deleted file mode 100644
index f8931ef..0000000
--- a/src/fonts/nimbus-sans-l/n019044l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019044l.pfm b/src/fonts/nimbus-sans-l/n019044l.pfm
deleted file mode 100644
index d89b9ff..0000000
--- a/src/fonts/nimbus-sans-l/n019044l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019063l.afm b/src/fonts/nimbus-sans-l/n019063l.afm
deleted file mode 100644
index cc26ac1..0000000
--- a/src/fonts/nimbus-sans-l/n019063l.afm
+++ /dev/null
@@ -1,1568 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 14:46:21 2007
-FontName NimbusSanL-ReguCondItal
-FullName Nimbus Sans L Regular Condensed Italic
-FamilyName Nimbus Sans L
-Weight Regular
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle -9.9
-IsFixedPitch false
-UnderlinePosition -100
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -139 -286 1021 959
-CapHeight 718
-XHeight 523
-Ascender 718
-Descender -207
-StartCharMetrics 562
-C 32 ; WX 228 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 228 ; N exclam ; B 74 0 278 718 ;
-C 34 ; WX 291 ; N quotedbl ; B 138 463 359 718 ;
-C 35 ; WX 456 ; N numbersign ; B 60 0 517 688 ;
-C 36 ; WX 456 ; N dollar ; B 57 -115 506 775 ;
-C 37 ; WX 729 ; N percent ; B 120 -19 729 703 ;
-C 38 ; WX 547 ; N ampersand ; B 63 -15 530 718 ;
-C 39 ; WX 182 ; N quoteright ; B 124 463 254 718 ;
-C 40 ; WX 273 ; N parenleft ; B 89 -207 372 733 ;
-C 41 ; WX 273 ; N parenright ; B -7 -207 276 733 ;
-C 42 ; WX 319 ; N asterisk ; B 135 431 389 718 ;
-C 43 ; WX 479 ; N plus ; B 70 0 497 505 ;
-C 44 ; WX 228 ; N comma ; B 46 -147 175 106 ;
-C 45 ; WX 273 ; N hyphen ; B 77 232 293 322 ;
-C 46 ; WX 228 ; N period ; B 71 0 175 106 ;
-C 47 ; WX 228 ; N slash ; B -17 -19 370 737 ;
-C 48 ; WX 456 ; N zero ; B 77 -19 499 703 ;
-C 49 ; WX 456 ; N one ; B 170 0 417 703 ;
-C 50 ; WX 456 ; N two ; B 21 0 506 703 ;
-C 51 ; WX 456 ; N three ; B 61 -19 500 703 ;
-C 52 ; WX 456 ; N four ; B 50 0 472 703 ;
-C 53 ; WX 456 ; N five ; B 55 -19 509 688 ;
-C 54 ; WX 456 ; N six ; B 74 -19 504 703 ;
-C 55 ; WX 456 ; N seven ; B 112 0 549 688 ;
-C 56 ; WX 456 ; N eight ; B 60 -19 497 703 ;
-C 57 ; WX 456 ; N nine ; B 67 -19 499 703 ;
-C 58 ; WX 228 ; N colon ; B 71 0 247 516 ;
-C 59 ; WX 228 ; N semicolon ; B 46 -147 247 516 ;
-C 60 ; WX 479 ; N less ; B 77 10 526 496 ;
-C 61 ; WX 479 ; N equal ; B 52 115 515 390 ;
-C 62 ; WX 479 ; N greater ; B 41 10 490 496 ;
-C 63 ; WX 456 ; N question ; B 132 0 500 727 ;
-C 64 ; WX 832 ; N at ; B 176 -19 791 737 ;
-C 65 ; WX 547 ; N A ; B 11 0 536 718 ;
-C 66 ; WX 547 ; N B ; B 61 0 583 718 ;
-C 67 ; WX 592 ; N C ; B 88 -19 640 737 ;
-C 68 ; WX 592 ; N D ; B 66 0 626 718 ;
-C 69 ; WX 547 ; N E ; B 71 0 625 718 ;
-C 70 ; WX 501 ; N F ; B 71 0 603 718 ;
-C 71 ; WX 638 ; N G ; B 91 -19 655 737 ;
-C 72 ; WX 592 ; N H ; B 63 0 655 718 ;
-C 73 ; WX 228 ; N I ; B 75 0 279 718 ; L J IJ ;
-C 74 ; WX 410 ; N J ; B 39 -19 476 718 ;
-C 75 ; WX 547 ; N K ; B 62 0 662 718 ;
-C 76 ; WX 456 ; N L ; B 62 0 455 718 ; L periodcentered Ldot ;
-C 77 ; WX 683 ; N M ; B 60 0 749 718 ;
-C 78 ; WX 592 ; N N ; B 62 0 655 718 ; L o afii61352 ;
-C 79 ; WX 638 ; N O ; B 86 -19 677 737 ;
-C 80 ; WX 547 ; N P ; B 71 0 604 718 ;
-C 81 ; WX 638 ; N Q ; B 86 -56 677 737 ;
-C 82 ; WX 592 ; N R ; B 72 0 634 718 ;
-C 83 ; WX 547 ; N S ; B 74 -19 584 737 ;
-C 84 ; WX 501 ; N T ; B 122 0 615 718 ; L M trademark ;
-C 85 ; WX 592 ; N U ; B 101 -19 653 718 ;
-C 86 ; WX 547 ; N V ; B 142 0 656 718 ;
-C 87 ; WX 774 ; N W ; B 138 0 886 718 ;
-C 88 ; WX 547 ; N X ; B 16 0 647 718 ;
-C 89 ; WX 547 ; N Y ; B 137 0 661 718 ;
-C 90 ; WX 501 ; N Z ; B 19 0 607 718 ;
-C 91 ; WX 228 ; N bracketleft ; B 17 -196 331 722 ;
-C 92 ; WX 228 ; N backslash ; B 115 -19 239 737 ;
-C 93 ; WX 228 ; N bracketright ; B -11 -196 302 722 ;
-C 94 ; WX 385 ; N asciicircum ; B 35 264 442 688 ;
-C 95 ; WX 456 ; N underscore ; B -22 -125 443 -75 ;
-C 96 ; WX 182 ; N quoteleft ; B 135 470 265 725 ;
-C 97 ; WX 456 ; N a ; B 50 -15 458 538 ;
-C 98 ; WX 456 ; N b ; B 48 -15 479 718 ;
-C 99 ; WX 410 ; N c ; B 61 -15 454 538 ;
-C 100 ; WX 456 ; N d ; B 69 -15 534 718 ;
-C 101 ; WX 456 ; N e ; B 69 -15 474 538 ;
-C 102 ; WX 228 ; N f ; B 71 0 341 728 ; L l fl ; L i fi ;
-C 103 ; WX 456 ; N g ; B 34 -220 500 538 ;
-C 104 ; WX 456 ; N h ; B 53 0 470 718 ;
-C 105 ; WX 182 ; N i ; B 55 0 252 718 ; L j ij ;
-C 106 ; WX 182 ; N j ; B -49 -210 252 718 ;
-C 107 ; WX 410 ; N k ; B 55 0 492 718 ;
-C 108 ; WX 182 ; N l ; B 55 0 252 718 ; L periodcentered ldot ;
-C 109 ; WX 683 ; N m ; B 53 0 699 538 ;
-C 110 ; WX 456 ; N n ; B 53 0 470 538 ;
-C 111 ; WX 456 ; N o ; B 68 -14 479 538 ;
-C 112 ; WX 456 ; N p ; B 11 -207 479 538 ;
-C 113 ; WX 456 ; N q ; B 69 -207 496 538 ;
-C 114 ; WX 273 ; N r ; B 63 0 365 538 ;
-C 115 ; WX 410 ; N s ; B 52 -15 434 538 ;
-C 116 ; WX 228 ; N t ; B 84 -7 302 669 ;
-C 117 ; WX 456 ; N u ; B 77 -15 492 523 ;
-C 118 ; WX 410 ; N v ; B 98 0 495 523 ;
-C 119 ; WX 592 ; N w ; B 103 0 673 523 ;
-C 120 ; WX 410 ; N x ; B 9 0 487 523 ;
-C 121 ; WX 410 ; N y ; B 12 -214 492 523 ;
-C 122 ; WX 410 ; N z ; B 25 0 468 523 ;
-C 123 ; WX 274 ; N braceleft ; B 75 -196 365 722 ;
-C 124 ; WX 213 ; N bar ; B 74 -19 265 737 ;
-C 125 ; WX 274 ; N braceright ; B 0 -196 291 722 ;
-C 126 ; WX 479 ; N asciitilde ; B 91 181 476 322 ;
-C 161 ; WX 273 ; N exclamdown ; B 63 -195 267 523 ;
-C 162 ; WX 456 ; N cent ; B 78 -115 479 623 ;
-C 163 ; WX 456 ; N sterling ; B 40 -16 520 718 ;
-C 164 ; WX 137 ; N fraction ; B -139 -19 396 703 ;
-C 165 ; WX 456 ; N yen ; B 67 0 573 688 ;
-C 166 ; WX 456 ; N florin ; B -43 -207 537 737 ;
-C 167 ; WX 456 ; N section ; B 63 -191 479 737 ;
-C 168 ; WX 456 ; N currency ; B 49 99 530 603 ;
-C 169 ; WX 157 ; N quotesingle ; B 129 463 233 718 ;
-C 170 ; WX 273 ; N quotedblleft ; B 113 470 378 725 ;
-C 171 ; WX 456 ; N guillemotleft ; B 120 108 454 446 ;
-C 172 ; WX 273 ; N guilsinglleft ; B 112 108 279 446 ;
-C 173 ; WX 273 ; N guilsinglright ; B 91 108 257 446 ;
-C 174 ; WX 410 ; N fi ; B 71 0 481 728 ;
-C 175 ; WX 410 ; N fl ; B 71 0 479 728 ;
-C 177 ; WX 456 ; N endash ; B 42 240 510 313 ;
-C 178 ; WX 456 ; N dagger ; B 110 -159 510 718 ;
-C 179 ; WX 456 ; N daggerdbl ; B 43 -159 511 718 ;
-C 180 ; WX 228 ; N periodcentered ; B 106 190 211 315 ;
-C 182 ; WX 440 ; N paragraph ; B 103 -173 533 718 ;
-C 183 ; WX 287 ; N bullet ; B 74 202 339 517 ;
-C 184 ; WX 182 ; N quotesinglbase ; B 17 -149 147 106 ;
-C 185 ; WX 273 ; N quotedblbase ; B -5 -149 260 106 ;
-C 186 ; WX 273 ; N quotedblright ; B 102 463 367 718 ;
-C 187 ; WX 456 ; N guillemotright ; B 98 108 433 446 ;
-C 188 ; WX 820 ; N ellipsis ; B 94 0 744 106 ;
-C 189 ; WX 820 ; N perthousand ; B 72 -19 844 703 ;
-C 191 ; WX 501 ; N questiondown ; B 70 -201 438 525 ;
-C 193 ; WX 273 ; N grave ; B 139 593 276 734 ;
-C 194 ; WX 273 ; N acute ; B 203 593 390 734 ;
-C 195 ; WX 273 ; N circumflex ; B 121 593 359 734 ;
-C 196 ; WX 273 ; N tilde ; B 102 606 402 722 ;
-C 197 ; WX 273 ; N macron ; B 117 627 384 684 ;
-C 198 ; WX 273 ; N breve ; B 137 595 391 731 ;
-C 199 ; WX 273 ; N dotaccent ; B 204 604 297 706 ;
-C 200 ; WX 273 ; N dieresis ; B 138 604 363 706 ;
-C 202 ; WX 273 ; N ring ; B 175 572 330 756 ;
-C 203 ; WX 273 ; N cedilla ; B 2 -225 191 0 ;
-C 205 ; WX 273 ; N hungarumlaut ; B 129 593 463 734 ;
-C 206 ; WX 273 ; N ogonek ; B 35 -225 204 0 ;
-C 207 ; WX 273 ; N caron ; B 145 593 384 734 ;
-C 208 ; WX 820 ; N emdash ; B 42 240 875 313 ;
-C 225 ; WX 820 ; N AE ; B 7 0 899 718 ;
-C 227 ; WX 303 ; N ordfeminine ; B 82 304 368 737 ;
-C 232 ; WX 456 ; N Lslash ; B 34 0 455 718 ;
-C 233 ; WX 638 ; N Oslash ; B 35 -19 730 737 ;
-C 234 ; WX 820 ; N OE ; B 80 -19 915 737 ;
-C 235 ; WX 299 ; N ordmasculine ; B 82 304 384 737 ;
-C 241 ; WX 729 ; N ae ; B 50 -15 746 538 ;
-C 245 ; WX 228 ; N dotlessi ; B 78 0 241 523 ;
-C 248 ; WX 182 ; N lslash ; B 34 0 284 718 ;
-C 249 ; WX 501 ; N oslash ; B 24 -22 531 545 ;
-C 250 ; WX 774 ; N oe ; B 68 -15 791 538 ;
-C 251 ; WX 501 ; N germandbls ; B 55 -15 539 728 ;
-C -1 ; WX 547 ; N Adieresis ; B 11 0 536 901 ;
-C -1 ; WX 547 ; N Aacute ; B 11 0 561 929 ;
-C -1 ; WX 547 ; N Agrave ; B 11 0 536 929 ;
-C -1 ; WX 547 ; N Acircumflex ; B 11 0 536 929 ;
-C -1 ; WX 547 ; N Abreve ; B 11 0 562 926 ;
-C -1 ; WX 547 ; N Atilde ; B 11 0 573 917 ;
-C -1 ; WX 547 ; N Aring ; B 11 0 536 944 ;
-C -1 ; WX 547 ; N Aogonek ; B 11 -225 536 718 ;
-C -1 ; WX 592 ; N Ccedilla ; B 88 -225 640 737 ;
-C -1 ; WX 592 ; N Cacute ; B 88 -19 640 929 ;
-C -1 ; WX 592 ; N Ccaron ; B 88 -19 640 929 ;
-C -1 ; WX 592 ; N Dcaron ; B 66 0 626 929 ;
-C -1 ; WX 547 ; N Edieresis ; B 71 0 625 901 ;
-C -1 ; WX 547 ; N Eacute ; B 71 0 625 929 ;
-C -1 ; WX 547 ; N Egrave ; B 71 0 625 929 ;
-C -1 ; WX 547 ; N Ecircumflex ; B 71 0 625 929 ;
-C -1 ; WX 547 ; N Ecaron ; B 71 0 625 929 ;
-C -1 ; WX 547 ; N Edotaccent ; B 71 0 625 901 ;
-C -1 ; WX 547 ; N Eogonek ; B 71 -225 625 718 ;
-C -1 ; WX 638 ; N Gbreve ; B 91 -19 655 926 ;
-C -1 ; WX 228 ; N Idieresis ; B 75 0 375 901 ;
-C -1 ; WX 228 ; N Iacute ; B 75 0 401 929 ;
-C -1 ; WX 228 ; N Igrave ; B 75 0 288 929 ;
-C -1 ; WX 228 ; N Icircumflex ; B 75 0 370 929 ;
-C -1 ; WX 228 ; N Idotaccent ; B 75 0 308 901 ;
-C -1 ; WX 456 ; N Lacute ; B 62 0 455 929 ;
-C -1 ; WX 456 ; N Lcaron ; B 62 0 536 718 ;
-C -1 ; WX 592 ; N Nacute ; B 62 0 655 929 ;
-C -1 ; WX 592 ; N Ncaron ; B 62 0 655 929 ;
-C -1 ; WX 592 ; N Ntilde ; B 62 0 655 917 ;
-C -1 ; WX 638 ; N Odieresis ; B 86 -19 677 901 ;
-C -1 ; WX 638 ; N Oacute ; B 86 -19 677 929 ;
-C -1 ; WX 638 ; N Ograve ; B 86 -19 677 929 ;
-C -1 ; WX 638 ; N Ocircumflex ; B 86 -19 677 929 ;
-C -1 ; WX 638 ; N Otilde ; B 86 -19 677 917 ;
-C -1 ; WX 638 ; N Ohungarumlaut ; B 86 -19 679 929 ;
-C -1 ; WX 592 ; N Racute ; B 72 0 634 929 ;
-C -1 ; WX 592 ; N Rcaron ; B 72 0 634 929 ;
-C -1 ; WX 547 ; N Sacute ; B 74 -19 584 929 ;
-C -1 ; WX 547 ; N Scaron ; B 74 -19 584 929 ;
-C -1 ; WX 547 ; N Scedilla ; B 74 -225 584 737 ;
-C -1 ; WX 501 ; N Tcaron ; B 122 0 615 929 ;
-C -1 ; WX 592 ; N Udieresis ; B 101 -19 653 901 ;
-C -1 ; WX 592 ; N Uacute ; B 101 -19 653 929 ;
-C -1 ; WX 592 ; N Ugrave ; B 101 -19 653 929 ;
-C -1 ; WX 592 ; N Ucircumflex ; B 101 -19 653 929 ;
-C -1 ; WX 592 ; N Uring ; B 101 -19 653 951 ;
-C -1 ; WX 592 ; N Uhungarumlaut ; B 101 -19 656 929 ;
-C -1 ; WX 547 ; N Yacute ; B 137 0 661 929 ;
-C -1 ; WX 501 ; N Zacute ; B 19 0 607 929 ;
-C -1 ; WX 501 ; N Zcaron ; B 19 0 607 929 ;
-C -1 ; WX 501 ; N Zdotaccent ; B 19 0 607 901 ;
-C -1 ; WX 547 ; N Amacron ; B 11 0 555 879 ;
-C -1 ; WX 501 ; N Tcommaaccent ; B 122 -286 615 718 ;
-C -1 ; WX 547 ; N Ydieresis ; B 137 0 661 901 ;
-C -1 ; WX 547 ; N Emacron ; B 71 0 625 879 ;
-C -1 ; WX 228 ; N Imacron ; B 75 0 395 879 ;
-C -1 ; WX 228 ; N Iogonek ; B -15 -225 279 718 ;
-C -1 ; WX 547 ; N Kcommaaccent ; B 62 -286 662 718 ;
-C -1 ; WX 456 ; N Lcommaaccent ; B 62 -286 455 718 ;
-C -1 ; WX 592 ; N Ncommaaccent ; B 62 -286 655 718 ;
-C -1 ; WX 638 ; N Omacron ; B 86 -19 677 879 ;
-C -1 ; WX 592 ; N Rcommaaccent ; B 72 -286 634 718 ;
-C -1 ; WX 638 ; N Gcommaaccent ; B 91 -286 655 737 ;
-C -1 ; WX 592 ; N Umacron ; B 101 -19 653 879 ;
-C -1 ; WX 592 ; N Uogonek ; B 101 -225 653 718 ;
-C -1 ; WX 456 ; N adieresis ; B 50 -15 458 706 ;
-C -1 ; WX 456 ; N aacute ; B 50 -15 482 734 ;
-C -1 ; WX 456 ; N agrave ; B 50 -15 458 734 ;
-C -1 ; WX 456 ; N acircumflex ; B 50 -15 458 734 ;
-C -1 ; WX 456 ; N abreve ; B 50 -15 482 731 ;
-C -1 ; WX 456 ; N atilde ; B 50 -15 486 722 ;
-C -1 ; WX 456 ; N aring ; B 50 -15 458 769 ;
-C -1 ; WX 456 ; N aogonek ; B 50 -225 458 538 ;
-C -1 ; WX 410 ; N cacute ; B 61 -15 480 734 ;
-C -1 ; WX 410 ; N ccaron ; B 61 -15 484 734 ;
-C -1 ; WX 410 ; N ccedilla ; B 61 -225 454 538 ;
-C -1 ; WX 503 ; N dcaron ; B 69 -15 643 718 ;
-C -1 ; WX 456 ; N edieresis ; B 69 -15 474 706 ;
-C -1 ; WX 456 ; N eacute ; B 69 -15 482 734 ;
-C -1 ; WX 456 ; N egrave ; B 69 -15 474 734 ;
-C -1 ; WX 456 ; N ecircumflex ; B 69 -15 474 734 ;
-C -1 ; WX 456 ; N ecaron ; B 69 -15 476 734 ;
-C -1 ; WX 456 ; N edotaccent ; B 69 -15 474 706 ;
-C -1 ; WX 456 ; N eogonek ; B 69 -225 474 538 ;
-C -1 ; WX 456 ; N gbreve ; B 34 -220 500 731 ;
-C -1 ; WX 228 ; N idieresis ; B 78 0 341 706 ;
-C -1 ; WX 228 ; N iacute ; B 78 0 368 734 ;
-C -1 ; WX 228 ; N igrave ; B 78 0 254 734 ;
-C -1 ; WX 228 ; N icircumflex ; B 78 0 336 734 ;
-C -1 ; WX 182 ; N lacute ; B 55 0 378 929 ;
-C -1 ; WX 217 ; N lcaron ; B 55 0 357 718 ;
-C -1 ; WX 456 ; N nacute ; B 53 0 482 734 ;
-C -1 ; WX 456 ; N ncaron ; B 53 0 476 734 ;
-C -1 ; WX 456 ; N ntilde ; B 53 0 486 722 ;
-C -1 ; WX 456 ; N odieresis ; B 68 -14 479 706 ;
-C -1 ; WX 456 ; N oacute ; B 68 -14 482 734 ;
-C -1 ; WX 456 ; N ograve ; B 68 -14 479 734 ;
-C -1 ; WX 456 ; N ocircumflex ; B 68 -14 479 734 ;
-C -1 ; WX 456 ; N otilde ; B 68 -14 494 722 ;
-C -1 ; WX 456 ; N ohungarumlaut ; B 68 -14 555 734 ;
-C -1 ; WX 273 ; N racute ; B 63 0 390 734 ;
-C -1 ; WX 410 ; N sacute ; B 52 -15 459 734 ;
-C -1 ; WX 410 ; N scaron ; B 52 -15 453 734 ;
-C -1 ; WX 410 ; N scommaaccent ; B 52 -286 434 538 ;
-C -1 ; WX 254 ; N tcaron ; B 84 -7 394 718 ;
-C -1 ; WX 456 ; N udieresis ; B 77 -15 492 706 ;
-C -1 ; WX 456 ; N uacute ; B 77 -15 492 734 ;
-C -1 ; WX 456 ; N ugrave ; B 77 -15 492 734 ;
-C -1 ; WX 456 ; N ucircumflex ; B 77 -15 492 734 ;
-C -1 ; WX 456 ; N uring ; B 77 -15 492 756 ;
-C -1 ; WX 456 ; N uhungarumlaut ; B 77 -15 555 734 ;
-C -1 ; WX 410 ; N yacute ; B 12 -214 492 734 ;
-C -1 ; WX 410 ; N zacute ; B 25 0 468 734 ;
-C -1 ; WX 410 ; N zcaron ; B 25 0 468 734 ;
-C -1 ; WX 410 ; N zdotaccent ; B 25 0 468 706 ;
-C -1 ; WX 410 ; N ydieresis ; B 12 -214 492 706 ;
-C -1 ; WX 228 ; N tcommaaccent ; B 25 -286 302 669 ;
-C -1 ; WX 456 ; N amacron ; B 50 -15 476 684 ;
-C -1 ; WX 456 ; N emacron ; B 69 -15 476 684 ;
-C -1 ; WX 228 ; N imacron ; B 78 0 362 684 ;
-C -1 ; WX 410 ; N kcommaaccent ; B 55 -286 492 718 ;
-C -1 ; WX 182 ; N lcommaaccent ; B 2 -286 252 718 ;
-C -1 ; WX 456 ; N ncommaaccent ; B 53 -286 470 538 ;
-C -1 ; WX 456 ; N omacron ; B 68 -14 479 684 ;
-C -1 ; WX 273 ; N rcommaaccent ; B 8 -286 365 538 ;
-C -1 ; WX 456 ; N umacron ; B 77 -15 492 684 ;
-C -1 ; WX 456 ; N uogonek ; B 77 -225 492 523 ;
-C -1 ; WX 273 ; N rcaron ; B 63 0 384 734 ;
-C -1 ; WX 410 ; N scedilla ; B 52 -225 434 538 ;
-C -1 ; WX 456 ; N gcommaaccent ; B 34 -220 500 818 ;
-C -1 ; WX 182 ; N iogonek ; B -42 -225 252 718 ;
-C -1 ; WX 547 ; N Scommaaccent ; B 74 -286 584 737 ;
-C -1 ; WX 592 ; N Eth ; B 57 0 626 718 ;
-C -1 ; WX 592 ; N Dcroat ; B 57 0 626 718 ;
-C -1 ; WX 547 ; N Thorn ; B 71 0 584 718 ;
-C -1 ; WX 456 ; N dcroat ; B 69 -15 573 718 ;
-C -1 ; WX 456 ; N eth ; B 67 -15 506 737 ;
-C -1 ; WX 456 ; N thorn ; B 11 -207 479 718 ;
-C -1 ; WX 481 ; N Euro ; B 0 -13 535 670 ;
-C -1 ; WX 273 ; N onesuperior ; B 136 281 305 703 ;
-C -1 ; WX 273 ; N twosuperior ; B 52 281 368 714 ;
-C -1 ; WX 273 ; N threesuperior ; B 74 270 358 714 ;
-C -1 ; WX 328 ; N degree ; B 138 411 384 703 ;
-C -1 ; WX 479 ; N minus ; B 70 216 497 289 ;
-C -1 ; WX 479 ; N multiply ; B 41 0 526 506 ;
-C -1 ; WX 479 ; N divide ; B 70 -19 497 524 ;
-C -1 ; WX 820 ; N trademark ; B 152 306 866 718 ;
-C -1 ; WX 479 ; N plusminus ; B 32 0 507 561 ;
-C -1 ; WX 684 ; N onehalf ; B 93 -19 688 703 ;
-C -1 ; WX 684 ; N onequarter ; B 123 -19 658 703 ;
-C -1 ; WX 684 ; N threequarters ; B 106 -19 706 714 ;
-C -1 ; WX 273 ; N commaaccent ; B 47 -286 163 -60 ;
-C -1 ; WX 604 ; N copyright ; B 44 -19 687 737 ;
-C -1 ; WX 604 ; N registered ; B 44 -19 687 737 ;
-C -1 ; WX 405 ; N lozenge ; B 80 0 447 740 ;
-C -1 ; WX 502 ; N Delta ; B 5 0 499 688 ;
-C -1 ; WX 479 ; N notequal ; B 52 10 515 495 ;
-C -1 ; WX 450 ; N radical ; B 74 -74 593 927 ;
-C -1 ; WX 479 ; N lessequal ; B 39 0 543 594 ;
-C -1 ; WX 479 ; N greaterequal ; B 39 0 507 594 ;
-C -1 ; WX 479 ; N logicalnot ; B 87 108 515 390 ;
-C -1 ; WX 585 ; N summation ; B 12 -123 570 752 ;
-C -1 ; WX 405 ; N partialdiff ; B 21 -10 379 753 ;
-C -1 ; WX 213 ; N brokenbar ; B 74 -19 265 737 ;
-C -1 ; WX 456 ; N mu ; B 20 -207 492 523 ;
-C -1 ; WX 547 ; N afii10017 ; B 11 0 536 718 ;
-C -1 ; WX 568 ; N afii10018 ; B 61 0 605 718 ;
-C -1 ; WX 547 ; N afii10019 ; B 61 0 583 718 ;
-C -1 ; WX 501 ; N afii10020 ; B 71 0 603 718 ;
-C -1 ; WX 666 ; N afii10021 ; B -52 -120 640 718 ;
-C -1 ; WX 547 ; N afii10022 ; B 71 0 625 718 ;
-C -1 ; WX 547 ; N afii10023 ; B 71 0 625 901 ;
-C -1 ; WX 902 ; N afii10024 ; B 16 0 1021 718 ;
-C -1 ; WX 557 ; N afii10025 ; B 61 -19 562 737 ;
-C -1 ; WX 594 ; N afii10026 ; B 63 0 658 718 ;
-C -1 ; WX 596 ; N afii10027 ; B 63 0 658 926 ;
-C -1 ; WX 565 ; N afii10028 ; B 63 0 666 718 ;
-C -1 ; WX 581 ; N afii10029 ; B -42 0 577 718 ;
-C -1 ; WX 683 ; N afii10030 ; B 60 0 749 718 ;
-C -1 ; WX 592 ; N afii10031 ; B 63 0 655 718 ;
-C -1 ; WX 638 ; N afii10032 ; B 86 -19 677 737 ;
-C -1 ; WX 593 ; N afii10033 ; B 63 0 657 718 ;
-C -1 ; WX 547 ; N afii10034 ; B 71 0 604 718 ;
-C -1 ; WX 592 ; N afii10035 ; B 88 -19 640 737 ;
-C -1 ; WX 501 ; N afii10036 ; B 122 0 615 718 ;
-C -1 ; WX 568 ; N afii10037 ; B 85 0 669 718 ;
-C -1 ; WX 702 ; N afii10038 ; B 70 0 754 718 ;
-C -1 ; WX 547 ; N afii10039 ; B 16 0 647 718 ;
-C -1 ; WX 645 ; N afii10040 ; B 63 -120 657 718 ;
-C -1 ; WX 480 ; N afii10041 ; B 73 0 543 718 ;
-C -1 ; WX 696 ; N afii10042 ; B 63 0 760 718 ;
-C -1 ; WX 696 ; N afii10043 ; B 63 -120 760 718 ;
-C -1 ; WX 723 ; N afii10044 ; B 135 0 727 718 ;
-C -1 ; WX 781 ; N afii10045 ; B 63 0 845 718 ;
-C -1 ; WX 512 ; N afii10046 ; B 63 0 543 718 ;
-C -1 ; WX 590 ; N afii10047 ; B 80 -19 629 737 ;
-C -1 ; WX 915 ; N afii10048 ; B 63 -19 955 737 ;
-C -1 ; WX 554 ; N afii10049 ; B 16 0 588 718 ;
-C -1 ; WX 456 ; N afii10065 ; B 50 -15 458 538 ;
-C -1 ; WX 478 ; N afii10066 ; B 60 -14 552 776 ;
-C -1 ; WX 434 ; N afii10067 ; B 48 0 458 523 ;
-C -1 ; WX 322 ; N afii10068 ; B 48 0 414 523 ;
-C -1 ; WX 536 ; N afii10069 ; B -36 -125 505 523 ;
-C -1 ; WX 456 ; N afii10070 ; B 69 -15 474 538 ;
-C -1 ; WX 456 ; N afii10071 ; B 69 -15 474 706 ;
-C -1 ; WX 656 ; N afii10072 ; B 9 0 733 523 ;
-C -1 ; WX 410 ; N afii10073 ; B 53 -15 429 538 ;
-C -1 ; WX 471 ; N afii10074 ; B 53 0 495 523 ;
-C -1 ; WX 473 ; N afii10075 ; B 53 0 497 731 ;
-C -1 ; WX 411 ; N afii10076 ; B 55 0 493 523 ;
-C -1 ; WX 439 ; N afii10077 ; B -25 0 433 523 ;
-C -1 ; WX 555 ; N afii10078 ; B 53 0 579 523 ;
-C -1 ; WX 471 ; N afii10079 ; B 53 0 495 523 ;
-C -1 ; WX 456 ; N afii10080 ; B 68 -14 479 538 ;
-C -1 ; WX 471 ; N afii10081 ; B 53 0 495 523 ;
-C -1 ; WX 456 ; N afii10082 ; B 11 -207 479 538 ;
-C -1 ; WX 410 ; N afii10083 ; B 61 -15 454 538 ;
-C -1 ; WX 334 ; N afii10084 ; B 84 0 409 523 ;
-C -1 ; WX 412 ; N afii10085 ; B 9 -214 489 523 ;
-C -1 ; WX 745 ; N afii10086 ; B 69 -207 770 628 ;
-C -1 ; WX 410 ; N afii10087 ; B 9 0 487 523 ;
-C -1 ; WX 486 ; N afii10088 ; B 53 -125 495 523 ;
-C -1 ; WX 386 ; N afii10089 ; B 59 0 411 525 ;
-C -1 ; WX 605 ; N afii10090 ; B 53 0 629 523 ;
-C -1 ; WX 605 ; N afii10091 ; B 53 -125 629 523 ;
-C -1 ; WX 490 ; N afii10092 ; B 84 0 514 523 ;
-C -1 ; WX 601 ; N afii10093 ; B 53 0 625 523 ;
-C -1 ; WX 425 ; N afii10094 ; B 53 0 449 523 ;
-C -1 ; WX 430 ; N afii10095 ; B 68 -15 455 538 ;
-C -1 ; WX 668 ; N afii10096 ; B 53 -14 691 538 ;
-C -1 ; WX 463 ; N afii10097 ; B 9 0 487 523 ;
-C -1 ; WX 547 ; N uni0400 ; B 71 0 625 959 ;
-C -1 ; WX 621 ; N afii10051 ; B 122 -131 640 718 ;
-C -1 ; WX 501 ; N afii10052 ; B 71 0 603 893 ;
-C -1 ; WX 592 ; N afii10053 ; B 88 -19 641 737 ;
-C -1 ; WX 547 ; N afii10054 ; B 74 -19 584 737 ;
-C -1 ; WX 228 ; N afii10055 ; B 75 0 279 718 ;
-C -1 ; WX 228 ; N afii10056 ; B 75 0 375 901 ;
-C -1 ; WX 410 ; N afii10057 ; B 39 -19 476 718 ;
-C -1 ; WX 847 ; N afii10058 ; B -42 0 850 718 ;
-C -1 ; WX 882 ; N afii10059 ; B 63 0 930 718 ;
-C -1 ; WX 621 ; N afii10060 ; B 122 0 640 718 ;
-C -1 ; WX 565 ; N afii10061 ; B 63 0 666 893 ;
-C -1 ; WX 594 ; N uni040D ; B 63 0 658 959 ;
-C -1 ; WX 568 ; N afii10062 ; B 85 0 669 926 ;
-C -1 ; WX 593 ; N afii10145 ; B 63 -120 657 718 ;
-C -1 ; WX 456 ; N uni0450 ; B 69 -15 474 764 ;
-C -1 ; WX 497 ; N afii10099 ; B 85 -128 484 718 ;
-C -1 ; WX 322 ; N afii10100 ; B 48 0 414 707 ;
-C -1 ; WX 408 ; N afii10101 ; B 60 -15 453 538 ;
-C -1 ; WX 410 ; N afii10102 ; B 52 -15 434 538 ;
-C -1 ; WX 182 ; N afii10103 ; B 55 0 252 718 ;
-C -1 ; WX 228 ; N afii10104 ; B 78 0 341 706 ;
-C -1 ; WX 182 ; N afii10105 ; B -49 -210 252 718 ;
-C -1 ; WX 657 ; N afii10106 ; B -25 0 668 523 ;
-C -1 ; WX 777 ; N afii10107 ; B 53 0 727 525 ;
-C -1 ; WX 497 ; N afii10108 ; B 85 0 484 718 ;
-C -1 ; WX 411 ; N afii10109 ; B 55 0 493 707 ;
-C -1 ; WX 471 ; N uni045D ; B 53 0 495 764 ;
-C -1 ; WX 412 ; N afii10110 ; B 9 -214 489 731 ;
-C -1 ; WX 471 ; N afii10193 ; B 53 -125 495 523 ;
-C -1 ; WX 512 ; N uni048C ; B 63 0 543 718 ;
-C -1 ; WX 425 ; N uni048D ; B 53 0 450 524 ;
-C -1 ; WX 583 ; N uni048E ; B 71 0 622 718 ;
-C -1 ; WX 480 ; N uni048F ; B 11 -207 479 538 ;
-C -1 ; WX 516 ; N afii10050 ; B 71 0 619 799 ;
-C -1 ; WX 344 ; N afii10098 ; B 48 0 426 591 ;
-C -1 ; WX 501 ; N uni0492 ; B 57 0 603 718 ;
-C -1 ; WX 322 ; N uni0493 ; B 33 0 414 523 ;
-C -1 ; WX 501 ; N uni0494 ; B 71 -131 603 718 ;
-C -1 ; WX 402 ; N uni0495 ; B 48 -184 414 523 ;
-C -1 ; WX 902 ; N uni0496 ; B 16 -120 1021 718 ;
-C -1 ; WX 656 ; N uni0497 ; B 9 -125 733 523 ;
-C -1 ; WX 557 ; N uni0498 ; B 61 -225 562 737 ;
-C -1 ; WX 410 ; N uni0499 ; B 53 -225 429 538 ;
-C -1 ; WX 565 ; N uni049A ; B 63 -120 666 718 ;
-C -1 ; WX 411 ; N uni049B ; B 55 -125 493 523 ;
-C -1 ; WX 563 ; N uni049C ; B 63 0 666 718 ;
-C -1 ; WX 411 ; N uni049D ; B 55 0 493 523 ;
-C -1 ; WX 565 ; N uni049E ; B 63 0 666 718 ;
-C -1 ; WX 411 ; N uni049F ; B 55 0 493 523 ;
-C -1 ; WX 747 ; N uni04A0 ; B 135 0 849 718 ;
-C -1 ; WX 461 ; N uni04A1 ; B 84 0 554 523 ;
-C -1 ; WX 592 ; N uni04A2 ; B 63 -120 655 718 ;
-C -1 ; WX 471 ; N uni04A3 ; B 53 -125 495 525 ;
-C -1 ; WX 860 ; N uni04A4 ; B 63 0 962 718 ;
-C -1 ; WX 606 ; N uni04A5 ; B 53 0 698 523 ;
-C -1 ; WX 932 ; N uni04A6 ; B 63 -131 920 718 ;
-C -1 ; WX 690 ; N uni04A7 ; B 53 -184 681 523 ;
-C -1 ; WX 592 ; N uni04A8 ; B 88 -19 640 737 ;
-C -1 ; WX 410 ; N uni04A9 ; B 61 -15 454 538 ;
-C -1 ; WX 592 ; N uni04AA ; B 88 -225 640 737 ;
-C -1 ; WX 410 ; N uni04AB ; B 61 -225 454 538 ;
-C -1 ; WX 501 ; N uni04AC ; B 122 -120 615 718 ;
-C -1 ; WX 334 ; N uni04AD ; B 84 -125 409 523 ;
-C -1 ; WX 547 ; N uni04AE ; B 137 0 661 718 ;
-C -1 ; WX 547 ; N uni04AF ; B 135 -195 599 523 ;
-C -1 ; WX 547 ; N uni04B0 ; B 105 0 661 718 ;
-C -1 ; WX 547 ; N uni04B1 ; B 107 -195 599 523 ;
-C -1 ; WX 547 ; N uni04B2 ; B 16 -120 647 718 ;
-C -1 ; WX 410 ; N uni04B3 ; B 9 -125 487 523 ;
-C -1 ; WX 771 ; N uni04B4 ; B 122 -120 783 718 ;
-C -1 ; WX 486 ; N uni04B5 ; B 84 -125 557 523 ;
-C -1 ; WX 532 ; N uni04B6 ; B 73 -120 543 718 ;
-C -1 ; WX 411 ; N uni04B7 ; B 59 -125 411 525 ;
-C -1 ; WX 480 ; N uni04B8 ; B 73 0 543 718 ;
-C -1 ; WX 386 ; N uni04B9 ; B 59 0 411 525 ;
-C -1 ; WX 480 ; N uni04BA ; B 33 0 503 718 ;
-C -1 ; WX 386 ; N uni04BB ; B 59 0 411 525 ;
-C -1 ; WX 777 ; N uni04BC ; B 90 -19 816 737 ;
-C -1 ; WX 571 ; N uni04BD ; B 78 -15 605 538 ;
-C -1 ; WX 777 ; N uni04BE ; B 90 -225 816 737 ;
-C -1 ; WX 571 ; N uni04BF ; B 78 -225 605 538 ;
-C -1 ; WX 228 ; N uni04C0 ; B 75 0 279 718 ;
-C -1 ; WX 902 ; N uni04C1 ; B 16 0 1021 954 ;
-C -1 ; WX 656 ; N uni04C2 ; B 9 0 733 759 ;
-C -1 ; WX 565 ; N uni04C3 ; B 63 -132 666 718 ;
-C -1 ; WX 411 ; N uni04C4 ; B 55 -184 493 523 ;
-C -1 ; WX 592 ; N uni04C7 ; B 63 -131 655 718 ;
-C -1 ; WX 471 ; N uni04C8 ; B 53 -174 495 523 ;
-C -1 ; WX 480 ; N uni04CB ; B 73 -120 543 718 ;
-C -1 ; WX 386 ; N uni04CC ; B 59 -125 411 525 ;
-C -1 ; WX 547 ; N uni04D0 ; B 11 0 567 954 ;
-C -1 ; WX 456 ; N uni04D1 ; B 50 -15 493 759 ;
-C -1 ; WX 547 ; N uni04D2 ; B 11 0 538 920 ;
-C -1 ; WX 456 ; N uni04D3 ; B 50 -15 464 725 ;
-C -1 ; WX 820 ; N uni04D4 ; B 7 0 899 718 ;
-C -1 ; WX 729 ; N uni04D5 ; B 50 -15 746 538 ;
-C -1 ; WX 547 ; N uni04D6 ; B 71 0 625 954 ;
-C -1 ; WX 456 ; N uni04D7 ; B 69 -15 490 759 ;
-C -1 ; WX 590 ; N uni04D8 ; B 75 -19 629 737 ;
-C -1 ; WX 456 ; N afii10846 ; B 69 -15 474 538 ;
-C -1 ; WX 590 ; N uni04DA ; B 75 -19 629 859 ;
-C -1 ; WX 456 ; N uni04DB ; B 69 -15 474 660 ;
-C -1 ; WX 902 ; N uni04DC ; B 16 0 1021 920 ;
-C -1 ; WX 656 ; N uni04DD ; B 9 0 733 725 ;
-C -1 ; WX 557 ; N uni04DE ; B 61 -19 562 859 ;
-C -1 ; WX 410 ; N uni04DF ; B 53 -15 429 660 ;
-C -1 ; WX 557 ; N uni04E0 ; B 61 -19 635 718 ;
-C -1 ; WX 410 ; N uni04E1 ; B 53 -15 485 523 ;
-C -1 ; WX 594 ; N uni04E2 ; B 63 0 658 875 ;
-C -1 ; WX 471 ; N uni04E3 ; B 53 0 495 680 ;
-C -1 ; WX 594 ; N uni04E4 ; B 63 0 658 920 ;
-C -1 ; WX 471 ; N uni04E5 ; B 53 0 495 725 ;
-C -1 ; WX 638 ; N uni04E6 ; B 86 -19 677 920 ;
-C -1 ; WX 456 ; N uni04E7 ; B 68 -14 479 725 ;
-C -1 ; WX 638 ; N uni04E8 ; B 86 -19 677 737 ;
-C -1 ; WX 456 ; N uni04E9 ; B 68 -14 479 538 ;
-C -1 ; WX 638 ; N uni04EA ; B 86 -19 677 859 ;
-C -1 ; WX 456 ; N uni04EB ; B 68 -14 479 660 ;
-C -1 ; WX 590 ; N uni04EC ; B 80 -19 630 920 ;
-C -1 ; WX 430 ; N uni04ED ; B 68 -15 455 725 ;
-C -1 ; WX 568 ; N uni04EE ; B 85 0 669 875 ;
-C -1 ; WX 412 ; N uni04EF ; B 9 -214 489 680 ;
-C -1 ; WX 568 ; N uni04F0 ; B 85 0 669 920 ;
-C -1 ; WX 412 ; N uni04F1 ; B 9 -214 489 725 ;
-C -1 ; WX 568 ; N uni04F2 ; B 85 0 669 959 ;
-C -1 ; WX 412 ; N uni04F3 ; B 9 -214 490 764 ;
-C -1 ; WX 480 ; N uni04F4 ; B 73 0 543 899 ;
-C -1 ; WX 386 ; N uni04F5 ; B 59 0 411 730 ;
-C -1 ; WX 781 ; N uni04F8 ; B 63 0 845 920 ;
-C -1 ; WX 601 ; N uni04F9 ; B 53 0 625 725 ;
-C -1 ; WX 322 ; N uniF6C4 ; B 48 0 414 523 ;
-C -1 ; WX 442 ; N uniF6C5 ; B -2 -14 488 776 ;
-C -1 ; WX 536 ; N uniF6C6 ; B -36 -125 505 523 ;
-C -1 ; WX 471 ; N uniF6C7 ; B 53 0 495 523 ;
-C -1 ; WX 334 ; N uniF6C8 ; B 84 0 409 523 ;
-C -1 ; WX 592 ; N Ccircumflex ; B 88 -19 640 959 ;
-C -1 ; WX 410 ; N ccircumflex ; B 61 -15 454 764 ;
-C -1 ; WX 592 ; N Cdotaccent ; B 88 -19 640 920 ;
-C -1 ; WX 410 ; N cdotaccent ; B 61 -15 454 725 ;
-C -1 ; WX 547 ; N Ebreve ; B 71 0 625 954 ;
-C -1 ; WX 456 ; N ebreve ; B 69 -15 490 759 ;
-C -1 ; WX 638 ; N Gcircumflex ; B 91 -19 655 959 ;
-C -1 ; WX 456 ; N gcircumflex ; B 34 -220 500 764 ;
-C -1 ; WX 638 ; N Gdotaccent ; B 91 -19 655 920 ;
-C -1 ; WX 456 ; N gdotaccent ; B 34 -220 500 725 ;
-C -1 ; WX 592 ; N Hcircumflex ; B 63 0 655 959 ;
-C -1 ; WX 456 ; N hcircumflex ; B 53 0 490 959 ;
-C -1 ; WX 632 ; N Hbar ; B 83 0 737 718 ;
-C -1 ; WX 456 ; N hbar ; B 53 0 470 718 ;
-C -1 ; WX 228 ; N Itilde ; B 75 0 417 934 ;
-C -1 ; WX 228 ; N itilde ; B 78 0 383 739 ;
-C -1 ; WX 228 ; N Ibreve ; B 75 0 408 954 ;
-C -1 ; WX 228 ; N ibreve ; B 78 0 373 759 ;
-C -1 ; WX 624 ; N IJ ; B 75 -19 676 718 ;
-C -1 ; WX 320 ; N ij ; B 55 -210 392 718 ;
-C -1 ; WX 410 ; N Jcircumflex ; B 39 -19 476 959 ;
-C -1 ; WX 182 ; N jcircumflex ; B -49 -210 359 734 ;
-C -1 ; WX 411 ; N kgreenlandic ; B 55 0 493 523 ;
-C -1 ; WX 456 ; N Ldot ; B 62 0 455 718 ;
-C -1 ; WX 410 ; N ldot ; B 55 0 393 718 ;
-C -1 ; WX 456 ; N napostrophe ; B 53 0 470 797 ;
-C -1 ; WX 592 ; N Eng ; B 62 -131 655 718 ;
-C -1 ; WX 456 ; N eng ; B 53 -174 470 538 ;
-C -1 ; WX 638 ; N Obreve ; B 86 -19 677 954 ;
-C -1 ; WX 456 ; N obreve ; B 68 -14 487 759 ;
-C -1 ; WX 547 ; N Scircumflex ; B 74 -19 584 959 ;
-C -1 ; WX 410 ; N scircumflex ; B 52 -15 434 764 ;
-C -1 ; WX 501 ; N Tbar ; B 101 0 615 718 ;
-C -1 ; WX 228 ; N tbar ; B 63 -7 302 669 ;
-C -1 ; WX 592 ; N Utilde ; B 101 -19 653 934 ;
-C -1 ; WX 456 ; N utilde ; B 77 -15 497 739 ;
-C -1 ; WX 592 ; N Ubreve ; B 101 -19 653 954 ;
-C -1 ; WX 456 ; N ubreve ; B 77 -15 492 759 ;
-C -1 ; WX 774 ; N Wcircumflex ; B 138 0 886 959 ;
-C -1 ; WX 592 ; N wcircumflex ; B 103 0 673 764 ;
-C -1 ; WX 547 ; N Ycircumflex ; B 137 0 661 959 ;
-C -1 ; WX 410 ; N ycircumflex ; B 12 -214 492 764 ;
-C -1 ; WX 228 ; N longs ; B 71 0 341 728 ;
-C -1 ; WX 858 ; N afii61352 ; B 62 0 882 718 ;
-C -1 ; WX 730 ; N infinity ; B 94 166 742 518 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 980
-KPX quoteright A -65
-KPX quoteright AE -67
-KPX quoteright Aacute -65
-KPX quoteright Adieresis -65
-KPX quoteright Aring -65
-KPX quoteright comma -52
-KPX quoteright d -20
-KPX quoteright o -29
-KPX quoteright period -52
-KPX quoteright r -19
-KPX quoteright s -17
-KPX quoteright t -9
-KPX quoteright v -3
-KPX quoteright w -3
-KPX quoteright y -4
-KPX comma one -88
-KPX comma quotedblright -27
-KPX comma quoteright -38
-KPX hyphen A -8
-KPX hyphen AE -8
-KPX hyphen Aacute -8
-KPX hyphen Adieresis -8
-KPX hyphen Aring -8
-KPX hyphen T -65
-KPX hyphen V -34
-KPX hyphen W -13
-KPX hyphen Y -72
-KPX period one -88
-KPX period quotedblright -28
-KPX period quoteright -39
-KPX zero four -2
-KPX zero one -40
-KPX zero seven -28
-KPX one comma -59
-KPX one eight -53
-KPX one five -53
-KPX one four -65
-KPX one nine -53
-KPX one one -96
-KPX one period -59
-KPX one seven -71
-KPX one six -51
-KPX one three -57
-KPX one two -57
-KPX one zero -50
-KPX two four -46
-KPX two one -37
-KPX two seven -21
-KPX three one -41
-KPX three seven -23
-KPX four four 1
-KPX four one -72
-KPX four seven -47
-KPX five four -3
-KPX five one -63
-KPX five seven -23
-KPX six four -1
-KPX six one -39
-KPX six seven -21
-KPX seven colon -55
-KPX seven comma -99
-KPX seven eight -24
-KPX seven five -30
-KPX seven four -76
-KPX seven one -42
-KPX seven period -99
-KPX seven seven -3
-KPX seven six -32
-KPX seven three -22
-KPX seven two -22
-KPX eight four -1
-KPX eight one -43
-KPX eight seven -24
-KPX nine four -6
-KPX nine one -40
-KPX nine seven -27
-KPX A C -29
-KPX A Ccedilla -29
-KPX A G -33
-KPX A O -30
-KPX A Odieresis -30
-KPX A Q -30
-KPX A T -81
-KPX A U -32
-KPX A Uacute -32
-KPX A Ucircumflex -32
-KPX A Udieresis -32
-KPX A Ugrave -32
-KPX A V -61
-KPX A W -43
-KPX A Y -82
-KPX A a -11
-KPX A b -6
-KPX A c -11
-KPX A ccedilla -11
-KPX A d -13
-KPX A e -15
-KPX A g -16
-KPX A guillemotleft -43
-KPX A guilsinglleft -39
-KPX A hyphen -6
-KPX A o -16
-KPX A period 1
-KPX A q -13
-KPX A quotedblright -40
-KPX A quoteright -51
-KPX A t -17
-KPX A u -15
-KPX A v -30
-KPX A w -25
-KPX A y -31
-KPX B A -22
-KPX B AE -21
-KPX B Aacute -22
-KPX B Acircumflex -22
-KPX B Adieresis -22
-KPX B Aring -22
-KPX B Atilde -22
-KPX B O -9
-KPX B OE -5
-KPX B Oacute -9
-KPX B Ocircumflex -9
-KPX B Odieresis -9
-KPX B Ograve -9
-KPX B Oslash -7
-KPX B V -34
-KPX B W -17
-KPX B Y -42
-KPX C A -32
-KPX C AE -31
-KPX C Aacute -32
-KPX C Adieresis -32
-KPX C Aring -32
-KPX C H -13
-KPX C K -13
-KPX C O -13
-KPX C Oacute -13
-KPX C Odieresis -13
-KPX D A -39
-KPX D Aacute -39
-KPX D Acircumflex -39
-KPX D Adieresis -39
-KPX D Agrave -39
-KPX D Aring -39
-KPX D Atilde -39
-KPX D J -9
-KPX D T -36
-KPX D V -37
-KPX D W -19
-KPX D X -42
-KPX D Y -55
-KPX F A -64
-KPX F Aacute -64
-KPX F Acircumflex -64
-KPX F Adieresis -64
-KPX F Agrave -64
-KPX F Aring -64
-KPX F Atilde -64
-KPX F J -59
-KPX F O -22
-KPX F Odieresis -22
-KPX F a -32
-KPX F aacute -32
-KPX F adieresis -32
-KPX F ae -32
-KPX F aring -32
-KPX F comma -107
-KPX F e -26
-KPX F eacute -26
-KPX F hyphen -18
-KPX F i -15
-KPX F j -15
-KPX F o -26
-KPX F oacute -26
-KPX F odieresis -26
-KPX F oe -24
-KPX F oslash -24
-KPX F period -107
-KPX F r -38
-KPX F u -34
-KPX G A -11
-KPX G AE -9
-KPX G Aacute -11
-KPX G Acircumflex -11
-KPX G Adieresis -11
-KPX G Agrave -11
-KPX G Aring -11
-KPX G Atilde -11
-KPX G T -38
-KPX G V -40
-KPX G W -23
-KPX G Y -58
-KPX J A -30
-KPX J AE -29
-KPX J Adieresis -30
-KPX J Aring -30
-KPX K C -41
-KPX K G -45
-KPX K O -42
-KPX K OE -37
-KPX K Oacute -42
-KPX K Odieresis -42
-KPX K S -38
-KPX K T 15
-KPX K a -15
-KPX K adieresis -15
-KPX K ae -15
-KPX K aring -15
-KPX K e -35
-KPX K hyphen -43
-KPX K o -36
-KPX K oacute -36
-KPX K odieresis -36
-KPX K u -29
-KPX K udieresis -29
-KPX K y -59
-KPX L A 10
-KPX L AE 12
-KPX L Aacute 10
-KPX L Adieresis 10
-KPX L Aring 10
-KPX L C -36
-KPX L Ccedilla -39
-KPX L G -40
-KPX L O -38
-KPX L Oacute -38
-KPX L Ocircumflex -38
-KPX L Odieresis -38
-KPX L Ograve -38
-KPX L Otilde -38
-KPX L S -20
-KPX L T -87
-KPX L U -34
-KPX L Udieresis -34
-KPX L V -87
-KPX L W -58
-KPX L Y -99
-KPX L hyphen -114
-KPX L quotedblright -108
-KPX L quoteright -120
-KPX L u -16
-KPX L udieresis -16
-KPX L y -53
-KPX N A -12
-KPX N AE -10
-KPX N Aacute -12
-KPX N Adieresis -12
-KPX N Aring -12
-KPX N C -6
-KPX N Ccedilla -5
-KPX N G -10
-KPX N O -6
-KPX N Oacute -6
-KPX N Odieresis -6
-KPX N a -8
-KPX N aacute -8
-KPX N adieresis -8
-KPX N ae -8
-KPX N aring -8
-KPX N comma -10
-KPX N e -5
-KPX N eacute -5
-KPX N o -6
-KPX N oacute -6
-KPX N odieresis -6
-KPX N oslash -1
-KPX N period -9
-KPX N u -4
-KPX N udieresis -5
-KPX O A -36
-KPX O AE -37
-KPX O Aacute -36
-KPX O Adieresis -36
-KPX O Aring -36
-KPX O T -34
-KPX O V -34
-KPX O W -16
-KPX O X -39
-KPX O Y -53
-KPX P A -71
-KPX P AE -72
-KPX P Aacute -71
-KPX P Adieresis -71
-KPX P Aring -71
-KPX P J -78
-KPX P a -27
-KPX P aacute -27
-KPX P adieresis -27
-KPX P ae -27
-KPX P aring -27
-KPX P comma -126
-KPX P e -31
-KPX P eacute -31
-KPX P hyphen -36
-KPX P o -31
-KPX P oacute -31
-KPX P odieresis -31
-KPX P oe -28
-KPX P oslash -29
-KPX P period -126
-KPX R C -11
-KPX R Ccedilla -10
-KPX R G -14
-KPX R O -11
-KPX R OE -7
-KPX R Oacute -11
-KPX R Odieresis -11
-KPX R T -19
-KPX R U -13
-KPX R Udieresis -13
-KPX R V -33
-KPX R W -17
-KPX R Y -39
-KPX R a -11
-KPX R aacute -11
-KPX R adieresis -11
-KPX R ae -11
-KPX R aring -11
-KPX R e -9
-KPX R eacute -9
-KPX R o -10
-KPX R oacute -10
-KPX R odieresis -10
-KPX R oe -9
-KPX R u -8
-KPX R uacute -8
-KPX R udieresis -8
-KPX R y -10
-KPX S A -22
-KPX S AE -21
-KPX S Aacute -22
-KPX S Adieresis -22
-KPX S Aring -22
-KPX S T -22
-KPX S V -36
-KPX S W -20
-KPX S Y -42
-KPX S t -10
-KPX T A -86
-KPX T AE -84
-KPX T Aacute -86
-KPX T Acircumflex -86
-KPX T Adieresis -86
-KPX T Agrave -86
-KPX T Aring -86
-KPX T Atilde -86
-KPX T C -34
-KPX T G -39
-KPX T J -88
-KPX T O -34
-KPX T OE -28
-KPX T Oacute -34
-KPX T Ocircumflex -34
-KPX T Odieresis -34
-KPX T Ograve -34
-KPX T Oslash -36
-KPX T Otilde -34
-KPX T S -23
-KPX T V 7
-KPX T W 10
-KPX T Y 9
-KPX T a -83
-KPX T ae -83
-KPX T c -76
-KPX T colon -106
-KPX T comma -84
-KPX T e -80
-KPX T g -78
-KPX T guillemotleft -104
-KPX T guilsinglleft -100
-KPX T hyphen -65
-KPX T i -9
-KPX T j -9
-KPX T o -81
-KPX T oslash -76
-KPX T period -84
-KPX T r -81
-KPX T s -78
-KPX T semicolon -102
-KPX T u -79
-KPX T v -87
-KPX T w -85
-KPX T y -88
-KPX U A -37
-KPX U AE -38
-KPX U Aacute -37
-KPX U Acircumflex -37
-KPX U Adieresis -37
-KPX U Aring -37
-KPX U Atilde -37
-KPX U comma -30
-KPX U m -9
-KPX U n -9
-KPX U p -7
-KPX U period -27
-KPX U r -14
-KPX V A -63
-KPX V AE -64
-KPX V Aacute -63
-KPX V Acircumflex -63
-KPX V Adieresis -63
-KPX V Agrave -63
-KPX V Aring -63
-KPX V Atilde -63
-KPX V C -36
-KPX V G -39
-KPX V O -36
-KPX V Oacute -36
-KPX V Ocircumflex -36
-KPX V Odieresis -36
-KPX V Ograve -36
-KPX V Oslash -33
-KPX V Otilde -36
-KPX V S -33
-KPX V T 12
-KPX V a -52
-KPX V ae -52
-KPX V colon -48
-KPX V comma -77
-KPX V e -50
-KPX V g -47
-KPX V guillemotleft -72
-KPX V guilsinglleft -68
-KPX V hyphen -33
-KPX V i -10
-KPX V o -51
-KPX V oslash -45
-KPX V period -77
-KPX V r -43
-KPX V semicolon -48
-KPX V u -40
-KPX V y -19
-KPX W A -46
-KPX W AE -47
-KPX W Aacute -46
-KPX W Acircumflex -46
-KPX W Adieresis -46
-KPX W Agrave -46
-KPX W Aring -46
-KPX W Atilde -46
-KPX W C -20
-KPX W G -23
-KPX W O -20
-KPX W Oacute -20
-KPX W Ocircumflex -20
-KPX W Odieresis -20
-KPX W Ograve -20
-KPX W Oslash -17
-KPX W Otilde -20
-KPX W S -25
-KPX W T 13
-KPX W a -32
-KPX W ae -32
-KPX W colon -38
-KPX W comma -50
-KPX W e -29
-KPX W g -27
-KPX W guillemotleft -52
-KPX W guilsinglleft -48
-KPX W hyphen -14
-KPX W i -9
-KPX W o -30
-KPX W oslash -25
-KPX W period -50
-KPX W r -30
-KPX W semicolon -38
-KPX W u -28
-KPX W y -10
-KPX X C -37
-KPX X O -37
-KPX X Odieresis -37
-KPX X Q -37
-KPX X a -20
-KPX X e -40
-KPX X hyphen -45
-KPX X o -41
-KPX X u -35
-KPX X y -50
-KPX Y A -84
-KPX Y AE -85
-KPX Y Aacute -84
-KPX Y Acircumflex -84
-KPX Y Adieresis -84
-KPX Y Agrave -84
-KPX Y Aring -84
-KPX Y Atilde -84
-KPX Y C -48
-KPX Y G -53
-KPX Y O -49
-KPX Y Oacute -49
-KPX Y Ocircumflex -49
-KPX Y Odieresis -49
-KPX Y Ograve -49
-KPX Y Oslash -50
-KPX Y Otilde -49
-KPX Y S -39
-KPX Y T 14
-KPX Y a -79
-KPX Y ae -79
-KPX Y colon -67
-KPX Y comma -95
-KPX Y e -77
-KPX Y g -75
-KPX Y guillemotleft -106
-KPX Y guilsinglleft -102
-KPX Y hyphen -72
-KPX Y i -8
-KPX Y o -78
-KPX Y oslash -72
-KPX Y p -53
-KPX Y period -95
-KPX Y semicolon -67
-KPX Y u -60
-KPX Y v -38
-KPX Z v -32
-KPX Z y -33
-KPX quoteleft A -57
-KPX quoteleft AE -60
-KPX quoteleft Aacute -57
-KPX quoteleft Adieresis -57
-KPX quoteleft Aring -57
-KPX quoteleft T -2
-KPX quoteleft V 7
-KPX quoteleft W 15
-KPX quoteleft Y -4
-KPX a j -9
-KPX a quoteright -13
-KPX a v -21
-KPX a w -16
-KPX a y -24
-KPX b v -15
-KPX b w -9
-KPX b y -19
-KPX c h -3
-KPX c k -4
-KPX e quoteright -8
-KPX e t -12
-KPX e v -18
-KPX e w -12
-KPX e x -22
-KPX e y -22
-KPX f a -14
-KPX f aacute -14
-KPX f adieresis -14
-KPX f ae -14
-KPX f aring -14
-KPX f e -16
-KPX f eacute -16
-KPX f f 11
-KPX f i -10
-KPX f j -10
-KPX f l -10
-KPX f o -17
-KPX f oacute -17
-KPX f odieresis -17
-KPX f oe -16
-KPX f oslash -11
-KPX f quoteright 1
-KPX f s -10
-KPX f t 11
-KPX g a -5
-KPX g adieresis -5
-KPX g ae -5
-KPX g aring -5
-KPX g e -3
-KPX g eacute -3
-KPX g oacute -3
-KPX g odieresis -3
-KPX g r -3
-KPX h quoteright -6
-KPX h y -18
-KPX i T -9
-KPX i j -3
-KPX k a -12
-KPX k aacute -12
-KPX k adieresis -12
-KPX k ae -13
-KPX k aring -12
-KPX k comma -5
-KPX k e -22
-KPX k eacute -22
-KPX k g -20
-KPX k hyphen -35
-KPX k o -23
-KPX k oacute -23
-KPX k odieresis -23
-KPX k period -4
-KPX k s -16
-KPX k u -8
-KPX k udieresis -8
-KPX l v -9
-KPX l y -10
-KPX m v -15
-KPX m w -10
-KPX m y -18
-KPX n T -79
-KPX n p -1
-KPX n quoteright -6
-KPX n v -16
-KPX n w -11
-KPX n y -18
-KPX o T -80
-KPX o quoteright -10
-KPX o t -10
-KPX o v -16
-KPX o w -10
-KPX o x -20
-KPX o y -20
-KPX p t -9
-KPX p y -19
-KPX q u -3
-KPX r a -9
-KPX r aacute -9
-KPX r acircumflex -9
-KPX r adieresis -9
-KPX r ae -9
-KPX r agrave -9
-KPX r aring -9
-KPX r c -11
-KPX r ccedilla -8
-KPX r colon -12
-KPX r comma -52
-KPX r d -9
-KPX r e -16
-KPX r eacute -16
-KPX r ecircumflex -16
-KPX r egrave -16
-KPX r f 17
-KPX r g -8
-KPX r h -4
-KPX r hyphen -34
-KPX r i -5
-KPX r j -5
-KPX r k -5
-KPX r l -5
-KPX r m -4
-KPX r n -4
-KPX r o -18
-KPX r oacute -18
-KPX r ocircumflex -18
-KPX r odieresis -18
-KPX r oe -15
-KPX r ograve -18
-KPX r oslash -15
-KPX r p -1
-KPX r period -52
-KPX r q -9
-KPX r quoteright 3
-KPX r r -9
-KPX r s -4
-KPX r semicolon -12
-KPX r t 17
-KPX r u -5
-KPX r v 17
-KPX r w 15
-KPX r x 12
-KPX r y 16
-KPX s quoteright -6
-KPX s t -11
-KPX t S -14
-KPX t a -5
-KPX t aacute -5
-KPX t adieresis -5
-KPX t ae -5
-KPX t aring -5
-KPX t colon -19
-KPX t e -12
-KPX t eacute -12
-KPX t h -6
-KPX t o -13
-KPX t oacute -13
-KPX t odieresis -13
-KPX t quoteright 2
-KPX t semicolon -19
-KPX v a -20
-KPX v aacute -20
-KPX v acircumflex -20
-KPX v adieresis -20
-KPX v ae -20
-KPX v agrave -20
-KPX v aring -20
-KPX v atilde -20
-KPX v c -15
-KPX v colon -14
-KPX v comma -54
-KPX v e -19
-KPX v eacute -19
-KPX v ecircumflex -19
-KPX v egrave -19
-KPX v g -17
-KPX v hyphen -7
-KPX v l -7
-KPX v o -20
-KPX v oacute -20
-KPX v odieresis -20
-KPX v ograve -20
-KPX v oslash -16
-KPX v period -54
-KPX v s -15
-KPX v semicolon -14
-KPX w a -16
-KPX w aacute -16
-KPX w acircumflex -16
-KPX w adieresis -16
-KPX w ae -16
-KPX w agrave -16
-KPX w aring -16
-KPX w atilde -16
-KPX w c -8
-KPX w colon -16
-KPX w comma -40
-KPX w e -12
-KPX w eacute -12
-KPX w ecircumflex -12
-KPX w egrave -12
-KPX w g -11
-KPX w l -9
-KPX w o -13
-KPX w oacute -13
-KPX w odieresis -13
-KPX w ograve -13
-KPX w oslash -8
-KPX w period -40
-KPX w s -11
-KPX w semicolon -16
-KPX x a -17
-KPX x c -16
-KPX x e -20
-KPX x eacute -20
-KPX x o -21
-KPX x q -17
-KPX y a -21
-KPX y aacute -21
-KPX y acircumflex -21
-KPX y adieresis -21
-KPX y ae -21
-KPX y agrave -21
-KPX y aring -21
-KPX y atilde -21
-KPX y c -16
-KPX y colon -15
-KPX y comma -54
-KPX y e -20
-KPX y eacute -20
-KPX y ecircumflex -20
-KPX y egrave -20
-KPX y g -19
-KPX y hyphen -6
-KPX y l -8
-KPX y o -21
-KPX y oacute -21
-KPX y odieresis -21
-KPX y ograve -21
-KPX y oslash -16
-KPX y period -53
-KPX y s -16
-KPX y semicolon -15
-KPX quotedblleft A -46
-KPX quotedblleft AE -49
-KPX quotedblleft Aacute -46
-KPX quotedblleft Adieresis -46
-KPX quotedblleft Aring -46
-KPX quotedblleft T 9
-KPX quotedblleft V 19
-KPX quotedblleft W 26
-KPX quotedblleft Y 7
-KPX guilsinglright A -43
-KPX guilsinglright AE -44
-KPX guilsinglright Aacute -43
-KPX guilsinglright Adieresis -43
-KPX guilsinglright Aring -43
-KPX guilsinglright T -100
-KPX guilsinglright V -68
-KPX guilsinglright W -46
-KPX guilsinglright Y -103
-KPX quotedblbase A 18
-KPX quotedblbase AE 19
-KPX quotedblbase T -64
-KPX quotedblbase V -57
-KPX quotedblbase W -30
-KPX quotedblbase Y -76
-KPX quotedblright A -54
-KPX quotedblright AE -56
-KPX quotedblright Aacute -54
-KPX quotedblright Adieresis -54
-KPX quotedblright Aring -54
-KPX quotedblright T 3
-KPX quotedblright V 11
-KPX quotedblright W 19
-KPX guillemotright A -47
-KPX guillemotright AE -47
-KPX guillemotright Aacute -47
-KPX guillemotright Adieresis -47
-KPX guillemotright Aring -47
-KPX guillemotright T -104
-KPX guillemotright V -72
-KPX guillemotright W -50
-KPX guillemotright Y -106
-KPX Oslash A -33
-KPX ae v -18
-KPX ae w -13
-KPX ae y -23
-KPX Adieresis C -29
-KPX Adieresis G -33
-KPX Adieresis O -30
-KPX Adieresis Q -30
-KPX Adieresis T -81
-KPX Adieresis U -32
-KPX Adieresis V -61
-KPX Adieresis W -43
-KPX Adieresis Y -82
-KPX Adieresis a -11
-KPX Adieresis b -6
-KPX Adieresis c -11
-KPX Adieresis d -13
-KPX Adieresis g -16
-KPX Adieresis guillemotleft -43
-KPX Adieresis guilsinglleft -39
-KPX Adieresis hyphen -6
-KPX Adieresis o -16
-KPX Adieresis period 1
-KPX Adieresis q -13
-KPX Adieresis quotedblright -40
-KPX Adieresis quoteright -51
-KPX Adieresis t -17
-KPX Adieresis u -15
-KPX Adieresis v -30
-KPX Adieresis w -25
-KPX Adieresis y -31
-KPX Aacute C -31
-KPX Aacute G -34
-KPX Aacute O -31
-KPX Aacute Q -31
-KPX Aacute T -81
-KPX Aacute U -33
-KPX Aacute V -61
-KPX Aacute W -43
-KPX Aacute Y -82
-KPX Aacute a -12
-KPX Aacute b -6
-KPX Aacute c -12
-KPX Aacute d -14
-KPX Aacute e -16
-KPX Aacute g -16
-KPX Aacute guillemotleft -44
-KPX Aacute guilsinglleft -40
-KPX Aacute hyphen -6
-KPX Aacute o -17
-KPX Aacute q -14
-KPX Aacute quoteright -51
-KPX Aacute t -18
-KPX Aacute u -16
-KPX Aacute v -30
-KPX Aacute w -25
-KPX Aacute y -31
-KPX Agrave C -29
-KPX Agrave G -33
-KPX Agrave O -30
-KPX Agrave Q -30
-KPX Agrave T -81
-KPX Agrave U -32
-KPX Agrave V -61
-KPX Agrave W -43
-KPX Agrave Y -82
-KPX Agrave period 1
-KPX Acircumflex C -29
-KPX Acircumflex G -33
-KPX Acircumflex O -30
-KPX Acircumflex Q -30
-KPX Acircumflex T -81
-KPX Acircumflex U -32
-KPX Acircumflex V -61
-KPX Acircumflex W -43
-KPX Acircumflex Y -82
-KPX Acircumflex period 1
-KPX Atilde C -31
-KPX Atilde G -35
-KPX Atilde O -31
-KPX Atilde Q -31
-KPX Atilde T -81
-KPX Atilde U -34
-KPX Atilde V -61
-KPX Atilde W -43
-KPX Atilde Y -82
-KPX Aring C -29
-KPX Aring G -33
-KPX Aring O -30
-KPX Aring Q -30
-KPX Aring T -81
-KPX Aring U -32
-KPX Aring V -61
-KPX Aring W -43
-KPX Aring Y -82
-KPX Aring a -11
-KPX Aring b -6
-KPX Aring c -11
-KPX Aring d -13
-KPX Aring e -15
-KPX Aring g -16
-KPX Aring guillemotleft -43
-KPX Aring guilsinglleft -39
-KPX Aring hyphen -6
-KPX Aring o -16
-KPX Aring period 1
-KPX Aring q -13
-KPX Aring quotedblright -40
-KPX Aring quoteright -51
-KPX Aring t -17
-KPX Aring u -15
-KPX Aring v -30
-KPX Aring w -25
-KPX Aring y -31
-KPX Ccedilla A -37
-KPX Odieresis A -36
-KPX Odieresis T -34
-KPX Odieresis V -34
-KPX Odieresis W -16
-KPX Odieresis X -39
-KPX Odieresis Y -53
-KPX Oacute A -36
-KPX Oacute T -34
-KPX Oacute V -34
-KPX Oacute W -16
-KPX Oacute Y -53
-KPX Ograve T -34
-KPX Ograve V -34
-KPX Ograve Y -53
-KPX Ocircumflex T -34
-KPX Ocircumflex V -34
-KPX Ocircumflex Y -53
-KPX Otilde T -34
-KPX Otilde V -34
-KPX Otilde Y -53
-KPX Udieresis A -37
-KPX Udieresis b -7
-KPX Udieresis comma -30
-KPX Udieresis m -9
-KPX Udieresis n -9
-KPX Udieresis p -7
-KPX Udieresis period -27
-KPX Udieresis r -14
-KPX Uacute A -37
-KPX Uacute comma -30
-KPX Uacute m -9
-KPX Uacute n -9
-KPX Uacute p -7
-KPX Uacute period -27
-KPX Uacute r -14
-KPX Ugrave A -37
-KPX Ucircumflex A -37
-KPX adieresis v -21
-KPX adieresis w -16
-KPX adieresis y -24
-KPX aacute v -22
-KPX aacute w -17
-KPX aacute y -24
-KPX agrave v -21
-KPX agrave w -16
-KPX agrave y -24
-KPX aring v -21
-KPX aring w -16
-KPX aring y -24
-KPX eacute v -18
-KPX eacute w -13
-KPX eacute y -22
-KPX ecircumflex v -18
-KPX ecircumflex w -12
-KPX ecircumflex y -22
-KPX odieresis t -10
-KPX odieresis v -16
-KPX odieresis w -10
-KPX odieresis x -20
-KPX odieresis y -20
-KPX oacute v -16
-KPX oacute w -10
-KPX oacute y -20
-KPX ograve v -16
-KPX ograve w -10
-KPX ograve y -20
-KPX ocircumflex t -10
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-sans-l/n019063l.pfb b/src/fonts/nimbus-sans-l/n019063l.pfb
deleted file mode 100644
index 0d41770..0000000
--- a/src/fonts/nimbus-sans-l/n019063l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019063l.pfm b/src/fonts/nimbus-sans-l/n019063l.pfm
deleted file mode 100644
index 59556b0..0000000
--- a/src/fonts/nimbus-sans-l/n019063l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019064l.afm b/src/fonts/nimbus-sans-l/n019064l.afm
deleted file mode 100644
index 67b0b78..0000000
--- a/src/fonts/nimbus-sans-l/n019064l.afm
+++ /dev/null
@@ -1,1569 +0,0 @@
-StartFontMetrics 2.0
-Comment Generated by FontForge 20070723
-Comment Creation Date: Thu Aug 2 14:45:44 2007
-FontName NimbusSanL-BoldCondItal
-FullName Nimbus Sans L Bold Condensed Italic
-FamilyName Nimbus Sans L
-Weight Bold
-Notice (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyrillic glyphs added by Valek Filippov (C) 2001-2005)
-ItalicAngle -9.9
-IsFixedPitch false
-UnderlinePosition -100
-UnderlineThickness 50
-Version 1.06
-EncodingScheme AdobeStandardEncoding
-FontBBox -143 -298 1001 989
-CapHeight 718
-XHeight 532
-Ascender 718
-Descender -207
-StartCharMetrics 562
-C 32 ; WX 228 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 273 ; N exclam ; B 77 0 325 718 ;
-C 34 ; WX 389 ; N quotedbl ; B 158 447 433 718 ;
-C 35 ; WX 456 ; N numbersign ; B 49 0 528 698 ;
-C 36 ; WX 456 ; N dollar ; B 55 -115 510 775 ;
-C 37 ; WX 729 ; N percent ; B 112 -19 739 710 ;
-C 38 ; WX 592 ; N ampersand ; B 73 -19 600 718 ;
-C 39 ; WX 228 ; N quoteright ; B 137 445 297 718 ;
-C 40 ; WX 273 ; N parenleft ; B 62 -207 385 734 ;
-C 41 ; WX 273 ; N parenright ; B -21 -207 302 734 ;
-C 42 ; WX 319 ; N asterisk ; B 120 387 394 718 ;
-C 43 ; WX 479 ; N plus ; B 67 0 500 506 ;
-C 44 ; WX 228 ; N comma ; B 23 -168 201 146 ;
-C 45 ; WX 273 ; N hyphen ; B 60 215 311 345 ;
-C 46 ; WX 228 ; N period ; B 52 0 201 146 ;
-C 47 ; WX 228 ; N slash ; B -30 -19 383 737 ;
-C 48 ; WX 456 ; N zero ; B 71 -19 506 710 ;
-C 49 ; WX 456 ; N one ; B 142 0 434 710 ;
-C 50 ; WX 456 ; N two ; B 21 0 508 710 ;
-C 51 ; WX 456 ; N three ; B 54 -19 499 710 ;
-C 52 ; WX 456 ; N four ; B 50 0 490 710 ;
-C 53 ; WX 456 ; N five ; B 53 -19 522 698 ;
-C 54 ; WX 456 ; N six ; B 70 -19 507 710 ;
-C 55 ; WX 456 ; N seven ; B 102 0 555 698 ;
-C 56 ; WX 456 ; N eight ; B 57 -19 505 710 ;
-C 57 ; WX 456 ; N nine ; B 64 -19 504 710 ;
-C 58 ; WX 273 ; N colon ; B 75 0 288 512 ;
-C 59 ; WX 273 ; N semicolon ; B 46 -168 288 512 ;
-C 60 ; WX 479 ; N less ; B 67 -15 537 521 ;
-C 61 ; WX 479 ; N equal ; B 48 87 519 419 ;
-C 62 ; WX 479 ; N greater ; B 30 -15 500 521 ;
-C 63 ; WX 501 ; N question ; B 135 0 550 727 ;
-C 64 ; WX 800 ; N at ; B 152 -19 782 737 ;
-C 65 ; WX 592 ; N A ; B 16 0 576 718 ;
-C 66 ; WX 592 ; N B ; B 62 0 626 718 ;
-C 67 ; WX 592 ; N C ; B 88 -19 647 737 ;
-C 68 ; WX 592 ; N D ; B 62 0 637 718 ;
-C 69 ; WX 547 ; N E ; B 62 0 620 718 ;
-C 70 ; WX 501 ; N F ; B 62 0 606 718 ;
-C 71 ; WX 638 ; N G ; B 89 -19 670 737 ;
-C 72 ; WX 592 ; N H ; B 58 0 659 718 ;
-C 73 ; WX 228 ; N I ; B 52 0 301 718 ; L J IJ ;
-C 74 ; WX 456 ; N J ; B 49 -18 522 718 ;
-C 75 ; WX 592 ; N K ; B 71 0 703 718 ;
-C 76 ; WX 501 ; N L ; B 62 0 501 718 ; L periodcentered Ldot ;
-C 77 ; WX 683 ; N M ; B 57 0 752 718 ;
-C 78 ; WX 592 ; N N ; B 57 0 661 718 ; L o afii61352 ;
-C 79 ; WX 638 ; N O ; B 88 -19 675 737 ;
-C 80 ; WX 547 ; N P ; B 62 0 605 718 ;
-C 81 ; WX 638 ; N Q ; B 88 -52 675 737 ;
-C 82 ; WX 592 ; N R ; B 62 0 638 718 ;
-C 83 ; WX 547 ; N S ; B 66 -19 588 737 ;
-C 84 ; WX 501 ; N T ; B 114 0 615 718 ; L M trademark ;
-C 85 ; WX 592 ; N U ; B 96 -19 659 718 ;
-C 86 ; WX 547 ; N V ; B 141 0 656 718 ;
-C 87 ; WX 774 ; N W ; B 138 0 887 718 ;
-C 88 ; WX 547 ; N X ; B 11 0 648 718 ;
-C 89 ; WX 547 ; N Y ; B 137 0 661 718 ;
-C 90 ; WX 501 ; N Z ; B 20 0 604 718 ;
-C 91 ; WX 273 ; N bracketleft ; B 17 -196 379 722 ;
-C 92 ; WX 228 ; N backslash ; B 101 -19 252 737 ;
-C 93 ; WX 273 ; N bracketright ; B -14 -196 347 722 ;
-C 94 ; WX 479 ; N asciicircum ; B 107 323 484 698 ;
-C 95 ; WX 456 ; N underscore ; B -22 -125 443 -75 ;
-C 96 ; WX 228 ; N quoteleft ; B 136 454 296 727 ;
-C 97 ; WX 456 ; N a ; B 45 -14 478 546 ;
-C 98 ; WX 501 ; N b ; B 50 -14 529 718 ;
-C 99 ; WX 456 ; N c ; B 65 -14 491 546 ;
-C 100 ; WX 501 ; N d ; B 67 -14 577 718 ;
-C 101 ; WX 456 ; N e ; B 58 -14 486 546 ;
-C 102 ; WX 273 ; N f ; B 71 0 385 727 ; L l fl ; L i fi ;
-C 103 ; WX 501 ; N g ; B 31 -217 546 546 ;
-C 104 ; WX 501 ; N h ; B 53 0 516 718 ;
-C 105 ; WX 228 ; N i ; B 57 0 298 725 ; L j ij ;
-C 106 ; WX 228 ; N j ; B -35 -214 298 725 ;
-C 107 ; WX 456 ; N k ; B 57 0 549 718 ;
-C 108 ; WX 228 ; N l ; B 57 0 297 718 ; L periodcentered ldot ;
-C 109 ; WX 729 ; N m ; B 52 0 746 546 ;
-C 110 ; WX 501 ; N n ; B 53 0 516 546 ;
-C 111 ; WX 501 ; N o ; B 67 -14 527 546 ;
-C 112 ; WX 501 ; N p ; B 15 -207 529 546 ;
-C 113 ; WX 501 ; N q ; B 66 -207 545 546 ;
-C 114 ; WX 319 ; N r ; B 52 0 401 546 ;
-C 115 ; WX 456 ; N s ; B 52 -14 479 546 ;
-C 116 ; WX 273 ; N t ; B 82 -6 346 676 ;
-C 117 ; WX 501 ; N u ; B 80 -14 540 532 ;
-C 118 ; WX 456 ; N v ; B 103 0 538 532 ;
-C 119 ; WX 638 ; N w ; B 101 0 723 532 ;
-C 120 ; WX 456 ; N x ; B 12 0 531 532 ;
-C 121 ; WX 456 ; N y ; B 34 -214 535 532 ;
-C 122 ; WX 410 ; N z ; B 16 0 478 532 ;
-C 123 ; WX 319 ; N braceleft ; B 77 -196 425 722 ;
-C 124 ; WX 230 ; N bar ; B 66 -19 289 737 ;
-C 125 ; WX 319 ; N braceright ; B -14 -196 333 722 ;
-C 126 ; WX 479 ; N asciitilde ; B 94 173 473 336 ;
-C 161 ; WX 273 ; N exclamdown ; B 41 -186 290 532 ;
-C 162 ; WX 456 ; N cent ; B 65 -118 491 628 ;
-C 163 ; WX 456 ; N sterling ; B 41 -16 520 718 ;
-C 164 ; WX 137 ; N fraction ; B -143 -19 399 710 ;
-C 165 ; WX 456 ; N yen ; B 49 0 585 698 ;
-C 166 ; WX 456 ; N florin ; B -41 -210 548 737 ;
-C 167 ; WX 456 ; N section ; B 50 -184 491 727 ;
-C 168 ; WX 456 ; N currency ; B 22 76 558 636 ;
-C 169 ; WX 195 ; N quotesingle ; B 135 447 263 718 ;
-C 170 ; WX 410 ; N quotedblleft ; B 132 454 482 727 ;
-C 171 ; WX 456 ; N guillemotleft ; B 111 76 468 484 ;
-C 172 ; WX 273 ; N guilsinglleft ; B 106 76 289 484 ;
-C 173 ; WX 273 ; N guilsinglright ; B 81 76 264 484 ;
-C 174 ; WX 501 ; N fi ; B 71 0 571 727 ;
-C 175 ; WX 501 ; N fl ; B 71 0 570 727 ;
-C 177 ; WX 456 ; N endash ; B 40 227 514 333 ;
-C 178 ; WX 456 ; N dagger ; B 97 -171 513 718 ;
-C 179 ; WX 456 ; N daggerdbl ; B 38 -171 515 718 ;
-C 180 ; WX 228 ; N periodcentered ; B 90 172 226 334 ;
-C 182 ; WX 456 ; N paragraph ; B 80 -191 564 700 ;
-C 183 ; WX 287 ; N bullet ; B 68 194 345 524 ;
-C 184 ; WX 228 ; N quotesinglbase ; B 34 -146 194 127 ;
-C 185 ; WX 410 ; N quotedblbase ; B 29 -146 380 127 ;
-C 186 ; WX 410 ; N quotedblright ; B 132 445 483 718 ;
-C 187 ; WX 456 ; N guillemotright ; B 85 76 443 484 ;
-C 188 ; WX 820 ; N ellipsis ; B 75 0 770 146 ;
-C 189 ; WX 820 ; N perthousand ; B 62 -19 851 710 ;
-C 191 ; WX 501 ; N questiondown ; B 44 -195 459 532 ;
-C 193 ; WX 273 ; N grave ; B 112 604 290 750 ;
-C 194 ; WX 273 ; N acute ; B 194 604 423 750 ;
-C 195 ; WX 273 ; N circumflex ; B 97 604 387 750 ;
-C 196 ; WX 273 ; N tilde ; B 92 610 415 737 ;
-C 197 ; WX 273 ; N macron ; B 100 604 396 678 ;
-C 198 ; WX 273 ; N breve ; B 128 604 405 750 ;
-C 199 ; WX 273 ; N dotaccent ; B 192 614 316 729 ;
-C 200 ; WX 273 ; N dieresis ; B 112 614 395 729 ;
-C 202 ; WX 273 ; N ring ; B 164 568 344 776 ;
-C 203 ; WX 273 ; N cedilla ; B -30 -228 180 0 ;
-C 205 ; WX 273 ; N hungarumlaut ; B 113 604 529 750 ;
-C 206 ; WX 273 ; N ogonek ; B 33 -228 216 0 ;
-C 207 ; WX 273 ; N caron ; B 123 604 412 750 ;
-C 208 ; WX 820 ; N emdash ; B 40 227 878 333 ;
-C 225 ; WX 820 ; N AE ; B 4 0 902 718 ;
-C 227 ; WX 303 ; N ordfeminine ; B 75 276 381 737 ;
-C 232 ; WX 501 ; N Lslash ; B 28 0 501 718 ;
-C 233 ; WX 638 ; N Oslash ; B 29 -27 733 745 ;
-C 234 ; WX 820 ; N OE ; B 81 -19 913 737 ;
-C 235 ; WX 299 ; N ordmasculine ; B 75 276 398 737 ;
-C 241 ; WX 729 ; N ae ; B 46 -14 757 546 ;
-C 245 ; WX 228 ; N dotlessi ; B 57 0 264 532 ;
-C 248 ; WX 228 ; N lslash ; B 33 0 334 718 ;
-C 249 ; WX 501 ; N oslash ; B 18 -29 575 560 ;
-C 250 ; WX 774 ; N oe ; B 67 -14 801 546 ;
-C 251 ; WX 501 ; N germandbls ; B 57 -14 539 731 ;
-C -1 ; WX 592 ; N Adieresis ; B 16 0 587 915 ;
-C -1 ; WX 592 ; N Aacute ; B 16 0 615 936 ;
-C -1 ; WX 592 ; N Agrave ; B 16 0 576 936 ;
-C -1 ; WX 592 ; N Acircumflex ; B 16 0 579 936 ;
-C -1 ; WX 592 ; N Abreve ; B 16 0 597 936 ;
-C -1 ; WX 592 ; N Atilde ; B 16 0 607 923 ;
-C -1 ; WX 592 ; N Aring ; B 16 0 576 989 ;
-C -1 ; WX 592 ; N Aogonek ; B 16 -228 576 718 ;
-C -1 ; WX 592 ; N Ccedilla ; B 88 -228 647 737 ;
-C -1 ; WX 592 ; N Cacute ; B 88 -19 647 936 ;
-C -1 ; WX 592 ; N Ccaron ; B 88 -19 647 936 ;
-C -1 ; WX 592 ; N Dcaron ; B 62 0 637 936 ;
-C -1 ; WX 547 ; N Edieresis ; B 62 0 620 915 ;
-C -1 ; WX 547 ; N Eacute ; B 62 0 620 936 ;
-C -1 ; WX 547 ; N Egrave ; B 62 0 620 936 ;
-C -1 ; WX 547 ; N Ecircumflex ; B 62 0 620 936 ;
-C -1 ; WX 547 ; N Ecaron ; B 62 0 620 936 ;
-C -1 ; WX 547 ; N Edotaccent ; B 62 0 620 915 ;
-C -1 ; WX 547 ; N Eogonek ; B 62 -228 620 718 ;
-C -1 ; WX 638 ; N Gbreve ; B 89 -19 670 936 ;
-C -1 ; WX 228 ; N Idieresis ; B 52 0 405 915 ;
-C -1 ; WX 228 ; N Iacute ; B 52 0 433 936 ;
-C -1 ; WX 228 ; N Igrave ; B 52 0 301 936 ;
-C -1 ; WX 228 ; N Icircumflex ; B 52 0 397 936 ;
-C -1 ; WX 228 ; N Idotaccent ; B 52 0 326 915 ;
-C -1 ; WX 501 ; N Lacute ; B 62 0 501 936 ;
-C -1 ; WX 501 ; N Lcaron ; B 62 0 573 718 ;
-C -1 ; WX 592 ; N Nacute ; B 57 0 661 936 ;
-C -1 ; WX 592 ; N Ncaron ; B 57 0 661 936 ;
-C -1 ; WX 592 ; N Ntilde ; B 57 0 661 923 ;
-C -1 ; WX 638 ; N Odieresis ; B 88 -19 675 915 ;
-C -1 ; WX 638 ; N Oacute ; B 88 -19 675 936 ;
-C -1 ; WX 638 ; N Ograve ; B 88 -19 675 936 ;
-C -1 ; WX 638 ; N Ocircumflex ; B 88 -19 675 936 ;
-C -1 ; WX 638 ; N Otilde ; B 88 -19 675 923 ;
-C -1 ; WX 638 ; N Ohungarumlaut ; B 88 -19 744 936 ;
-C -1 ; WX 592 ; N Racute ; B 62 0 638 936 ;
-C -1 ; WX 592 ; N Rcaron ; B 62 0 638 936 ;
-C -1 ; WX 547 ; N Sacute ; B 66 -19 592 936 ;
-C -1 ; WX 547 ; N Scaron ; B 66 -19 588 936 ;
-C -1 ; WX 547 ; N Scedilla ; B 66 -228 588 737 ;
-C -1 ; WX 501 ; N Tcaron ; B 114 0 615 936 ;
-C -1 ; WX 592 ; N Udieresis ; B 96 -19 659 915 ;
-C -1 ; WX 592 ; N Uacute ; B 96 -19 659 936 ;
-C -1 ; WX 592 ; N Ugrave ; B 96 -19 659 936 ;
-C -1 ; WX 592 ; N Ucircumflex ; B 96 -19 659 936 ;
-C -1 ; WX 592 ; N Uring ; B 96 -19 659 962 ;
-C -1 ; WX 592 ; N Uhungarumlaut ; B 96 -19 721 936 ;
-C -1 ; WX 547 ; N Yacute ; B 137 0 661 936 ;
-C -1 ; WX 501 ; N Zacute ; B 20 0 604 936 ;
-C -1 ; WX 501 ; N Zcaron ; B 20 0 604 936 ;
-C -1 ; WX 501 ; N Zdotaccent ; B 20 0 604 915 ;
-C -1 ; WX 592 ; N Amacron ; B 16 0 588 864 ;
-C -1 ; WX 501 ; N Tcommaaccent ; B 114 -298 615 718 ;
-C -1 ; WX 547 ; N Ydieresis ; B 137 0 661 915 ;
-C -1 ; WX 547 ; N Emacron ; B 62 0 620 864 ;
-C -1 ; WX 228 ; N Imacron ; B 52 0 406 864 ;
-C -1 ; WX 228 ; N Iogonek ; B -8 -228 301 718 ;
-C -1 ; WX 592 ; N Kcommaaccent ; B 71 -298 703 718 ;
-C -1 ; WX 501 ; N Lcommaaccent ; B 62 -298 501 718 ;
-C -1 ; WX 592 ; N Ncommaaccent ; B 57 -298 661 718 ;
-C -1 ; WX 638 ; N Omacron ; B 88 -19 675 864 ;
-C -1 ; WX 592 ; N Rcommaaccent ; B 62 -298 638 718 ;
-C -1 ; WX 638 ; N Gcommaaccent ; B 89 -298 670 737 ;
-C -1 ; WX 592 ; N Umacron ; B 96 -19 659 864 ;
-C -1 ; WX 592 ; N Uogonek ; B 96 -228 659 718 ;
-C -1 ; WX 456 ; N adieresis ; B 45 -14 487 729 ;
-C -1 ; WX 456 ; N aacute ; B 45 -14 514 750 ;
-C -1 ; WX 456 ; N agrave ; B 45 -14 478 750 ;
-C -1 ; WX 456 ; N acircumflex ; B 45 -14 478 750 ;
-C -1 ; WX 456 ; N abreve ; B 45 -14 496 750 ;
-C -1 ; WX 456 ; N atilde ; B 45 -14 507 737 ;
-C -1 ; WX 456 ; N aring ; B 45 -14 478 803 ;
-C -1 ; WX 456 ; N aogonek ; B 45 -228 478 546 ;
-C -1 ; WX 456 ; N cacute ; B 65 -14 515 750 ;
-C -1 ; WX 456 ; N ccaron ; B 65 -14 504 750 ;
-C -1 ; WX 456 ; N ccedilla ; B 65 -228 491 546 ;
-C -1 ; WX 561 ; N dcaron ; B 67 -14 701 718 ;
-C -1 ; WX 456 ; N edieresis ; B 58 -14 488 729 ;
-C -1 ; WX 456 ; N eacute ; B 58 -14 515 750 ;
-C -1 ; WX 456 ; N egrave ; B 58 -14 486 750 ;
-C -1 ; WX 456 ; N ecircumflex ; B 58 -14 486 750 ;
-C -1 ; WX 456 ; N ecaron ; B 58 -14 504 750 ;
-C -1 ; WX 456 ; N edotaccent ; B 58 -14 486 729 ;
-C -1 ; WX 456 ; N eogonek ; B 58 -228 486 546 ;
-C -1 ; WX 501 ; N gbreve ; B 31 -217 546 750 ;
-C -1 ; WX 228 ; N idieresis ; B 57 0 373 729 ;
-C -1 ; WX 228 ; N iacute ; B 57 0 401 750 ;
-C -1 ; WX 228 ; N igrave ; B 57 0 268 750 ;
-C -1 ; WX 228 ; N icircumflex ; B 57 0 365 750 ;
-C -1 ; WX 228 ; N lacute ; B 57 0 433 936 ;
-C -1 ; WX 283 ; N lcaron ; B 57 0 422 718 ;
-C -1 ; WX 501 ; N nacute ; B 53 0 537 750 ;
-C -1 ; WX 501 ; N ncaron ; B 53 0 526 750 ;
-C -1 ; WX 501 ; N ntilde ; B 53 0 529 737 ;
-C -1 ; WX 501 ; N odieresis ; B 67 -14 527 729 ;
-C -1 ; WX 501 ; N oacute ; B 67 -14 537 750 ;
-C -1 ; WX 501 ; N ograve ; B 67 -14 527 750 ;
-C -1 ; WX 501 ; N ocircumflex ; B 67 -14 527 750 ;
-C -1 ; WX 501 ; N otilde ; B 67 -14 529 737 ;
-C -1 ; WX 501 ; N ohungarumlaut ; B 67 -14 643 750 ;
-C -1 ; WX 319 ; N racute ; B 52 0 446 750 ;
-C -1 ; WX 456 ; N sacute ; B 52 -14 515 750 ;
-C -1 ; WX 456 ; N scaron ; B 52 -14 503 750 ;
-C -1 ; WX 456 ; N scommaaccent ; B 52 -298 479 546 ;
-C -1 ; WX 312 ; N tcaron ; B 82 -6 452 718 ;
-C -1 ; WX 501 ; N udieresis ; B 80 -14 540 729 ;
-C -1 ; WX 501 ; N uacute ; B 80 -14 540 750 ;
-C -1 ; WX 501 ; N ugrave ; B 80 -14 540 750 ;
-C -1 ; WX 501 ; N ucircumflex ; B 80 -14 540 750 ;
-C -1 ; WX 501 ; N uring ; B 80 -14 540 776 ;
-C -1 ; WX 501 ; N uhungarumlaut ; B 80 -14 643 750 ;
-C -1 ; WX 456 ; N yacute ; B 34 -214 535 750 ;
-C -1 ; WX 410 ; N zacute ; B 16 0 492 750 ;
-C -1 ; WX 410 ; N zcaron ; B 16 0 480 750 ;
-C -1 ; WX 410 ; N zdotaccent ; B 16 0 478 729 ;
-C -1 ; WX 456 ; N ydieresis ; B 34 -214 535 729 ;
-C -1 ; WX 273 ; N tcommaaccent ; B 35 -298 346 676 ;
-C -1 ; WX 456 ; N amacron ; B 45 -14 488 678 ;
-C -1 ; WX 456 ; N emacron ; B 58 -14 488 678 ;
-C -1 ; WX 228 ; N imacron ; B 57 0 374 678 ;
-C -1 ; WX 456 ; N kcommaaccent ; B 57 -298 549 718 ;
-C -1 ; WX 228 ; N lcommaaccent ; B 12 -298 297 718 ;
-C -1 ; WX 501 ; N ncommaaccent ; B 53 -298 516 546 ;
-C -1 ; WX 501 ; N omacron ; B 67 -14 527 678 ;
-C -1 ; WX 319 ; N rcommaaccent ; B 5 -298 401 546 ;
-C -1 ; WX 501 ; N umacron ; B 80 -14 540 678 ;
-C -1 ; WX 501 ; N uogonek ; B 80 -228 540 532 ;
-C -1 ; WX 319 ; N rcaron ; B 52 0 435 750 ;
-C -1 ; WX 456 ; N scedilla ; B 52 -228 479 546 ;
-C -1 ; WX 501 ; N gcommaaccent ; B 31 -217 546 844 ;
-C -1 ; WX 228 ; N iogonek ; B -11 -228 298 725 ;
-C -1 ; WX 547 ; N Scommaaccent ; B 66 -298 588 737 ;
-C -1 ; WX 592 ; N Eth ; B 51 0 637 718 ;
-C -1 ; WX 592 ; N Dcroat ; B 51 0 637 718 ;
-C -1 ; WX 547 ; N Thorn ; B 62 0 588 718 ;
-C -1 ; WX 501 ; N dcroat ; B 67 -14 617 718 ;
-C -1 ; WX 501 ; N eth ; B 67 -14 549 737 ;
-C -1 ; WX 501 ; N thorn ; B 15 -207 529 718 ;
-C -1 ; WX 467 ; N Euro ; B 0 -15 507 670 ;
-C -1 ; WX 273 ; N onesuperior ; B 121 283 318 710 ;
-C -1 ; WX 273 ; N twosuperior ; B 57 283 368 722 ;
-C -1 ; WX 273 ; N threesuperior ; B 75 271 361 722 ;
-C -1 ; WX 328 ; N degree ; B 143 426 383 712 ;
-C -1 ; WX 479 ; N minus ; B 67 197 500 309 ;
-C -1 ; WX 479 ; N multiply ; B 47 1 520 505 ;
-C -1 ; WX 479 ; N divide ; B 67 -42 500 548 ;
-C -1 ; WX 820 ; N trademark ; B 146 306 909 718 ;
-C -1 ; WX 479 ; N plusminus ; B 33 0 512 578 ;
-C -1 ; WX 684 ; N onehalf ; B 108 -19 704 710 ;
-C -1 ; WX 684 ; N onequarter ; B 108 -19 661 710 ;
-C -1 ; WX 684 ; N threequarters ; B 82 -19 688 722 ;
-C -1 ; WX 273 ; N commaaccent ; B 35 -298 175 -60 ;
-C -1 ; WX 604 ; N copyright ; B 46 -19 685 737 ;
-C -1 ; WX 604 ; N registered ; B 45 -19 684 737 ;
-C -1 ; WX 405 ; N lozenge ; B 80 0 447 740 ;
-C -1 ; WX 502 ; N Delta ; B 5 0 499 688 ;
-C -1 ; WX 479 ; N notequal ; B 48 -16 519 522 ;
-C -1 ; WX 450 ; N radical ; B 54 -35 605 918 ;
-C -1 ; WX 479 ; N lessequal ; B 34 0 565 672 ;
-C -1 ; WX 479 ; N greaterequal ; B 34 0 527 671 ;
-C -1 ; WX 479 ; N logicalnot ; B 86 108 519 419 ;
-C -1 ; WX 585 ; N summation ; B 12 -123 570 752 ;
-C -1 ; WX 405 ; N partialdiff ; B 39 -21 465 743 ;
-C -1 ; WX 230 ; N brokenbar ; B 66 -19 289 737 ;
-C -1 ; WX 501 ; N mu ; B 18 -207 540 532 ;
-C -1 ; WX 592 ; N afii10017 ; B 16 0 576 718 ;
-C -1 ; WX 592 ; N afii10018 ; B -1 0 544 718 ;
-C -1 ; WX 592 ; N afii10019 ; B 62 0 626 718 ;
-C -1 ; WX 501 ; N afii10020 ; B 62 0 606 718 ;
-C -1 ; WX 712 ; N afii10021 ; B -48 -120 689 718 ;
-C -1 ; WX 547 ; N afii10022 ; B 62 0 620 718 ;
-C -1 ; WX 547 ; N afii10023 ; B 62 0 620 915 ;
-C -1 ; WX 900 ; N afii10024 ; B 11 0 1001 718 ;
-C -1 ; WX 537 ; N afii10025 ; B 54 -19 581 737 ;
-C -1 ; WX 596 ; N afii10026 ; B 58 0 663 718 ;
-C -1 ; WX 596 ; N afii10027 ; B 58 0 663 936 ;
-C -1 ; WX 593 ; N afii10028 ; B 71 0 704 718 ;
-C -1 ; WX 592 ; N afii10029 ; B -48 0 604 718 ;
-C -1 ; WX 686 ; N afii10030 ; B 58 0 753 718 ;
-C -1 ; WX 592 ; N afii10031 ; B 58 0 659 718 ;
-C -1 ; WX 638 ; N afii10032 ; B 88 -19 675 737 ;
-C -1 ; WX 590 ; N afii10033 ; B 57 0 659 718 ;
-C -1 ; WX 547 ; N afii10034 ; B 62 0 605 718 ;
-C -1 ; WX 592 ; N afii10035 ; B 88 -19 647 737 ;
-C -1 ; WX 501 ; N afii10036 ; B 114 0 615 718 ;
-C -1 ; WX 547 ; N afii10037 ; B 86 0 661 718 ;
-C -1 ; WX 776 ; N afii10038 ; B 50 0 815 718 ;
-C -1 ; WX 547 ; N afii10039 ; B 11 0 648 718 ;
-C -1 ; WX 653 ; N afii10040 ; B 62 -120 676 718 ;
-C -1 ; WX 492 ; N afii10041 ; B 53 0 561 718 ;
-C -1 ; WX 744 ; N afii10042 ; B 62 0 813 718 ;
-C -1 ; WX 802 ; N afii10043 ; B 62 -120 825 718 ;
-C -1 ; WX 633 ; N afii10044 ; B 57 0 668 718 ;
-C -1 ; WX 727 ; N afii10045 ; B 62 0 796 718 ;
-C -1 ; WX 524 ; N afii10046 ; B 62 0 559 718 ;
-C -1 ; WX 606 ; N afii10047 ; B 88 -19 644 737 ;
-C -1 ; WX 914 ; N afii10048 ; B 57 -19 951 737 ;
-C -1 ; WX 570 ; N afii10049 ; B 16 0 624 718 ;
-C -1 ; WX 456 ; N afii10065 ; B 45 -14 478 546 ;
-C -1 ; WX 497 ; N afii10066 ; B 60 -14 612 776 ;
-C -1 ; WX 485 ; N afii10067 ; B 50 0 517 532 ;
-C -1 ; WX 380 ; N afii10068 ; B 50 0 462 532 ;
-C -1 ; WX 637 ; N afii10069 ; B -27 -120 593 532 ;
-C -1 ; WX 456 ; N afii10070 ; B 58 -14 486 546 ;
-C -1 ; WX 456 ; N afii10071 ; B 58 -14 488 729 ;
-C -1 ; WX 720 ; N afii10072 ; B 12 0 795 532 ;
-C -1 ; WX 457 ; N afii10073 ; B 53 -14 482 546 ;
-C -1 ; WX 503 ; N afii10074 ; B 53 0 542 532 ;
-C -1 ; WX 504 ; N afii10075 ; B 53 0 543 750 ;
-C -1 ; WX 457 ; N afii10076 ; B 57 0 550 532 ;
-C -1 ; WX 496 ; N afii10077 ; B -29 0 494 532 ;
-C -1 ; WX 648 ; N afii10078 ; B 53 0 687 532 ;
-C -1 ; WX 503 ; N afii10079 ; B 53 0 542 532 ;
-C -1 ; WX 501 ; N afii10080 ; B 67 -14 527 546 ;
-C -1 ; WX 503 ; N afii10081 ; B 53 0 542 532 ;
-C -1 ; WX 501 ; N afii10082 ; B 15 -207 529 546 ;
-C -1 ; WX 456 ; N afii10083 ; B 65 -14 491 546 ;
-C -1 ; WX 370 ; N afii10084 ; B 82 0 452 532 ;
-C -1 ; WX 456 ; N afii10085 ; B 34 -214 535 532 ;
-C -1 ; WX 786 ; N afii10086 ; B 66 -207 815 637 ;
-C -1 ; WX 456 ; N afii10087 ; B 12 0 531 532 ;
-C -1 ; WX 571 ; N afii10088 ; B 53 -120 581 532 ;
-C -1 ; WX 418 ; N afii10089 ; B 48 0 458 532 ;
-C -1 ; WX 678 ; N afii10090 ; B 53 0 717 532 ;
-C -1 ; WX 746 ; N afii10091 ; B 53 -120 756 532 ;
-C -1 ; WX 548 ; N afii10092 ; B 82 0 579 532 ;
-C -1 ; WX 687 ; N afii10093 ; B 53 0 726 532 ;
-C -1 ; WX 458 ; N afii10094 ; B 53 0 497 532 ;
-C -1 ; WX 462 ; N afii10095 ; B 66 -14 489 546 ;
-C -1 ; WX 723 ; N afii10096 ; B 53 -14 749 546 ;
-C -1 ; WX 487 ; N afii10097 ; B 32 0 526 532 ;
-C -1 ; WX 547 ; N uni0400 ; B 62 0 620 964 ;
-C -1 ; WX 650 ; N afii10051 ; B 114 -138 657 718 ;
-C -1 ; WX 501 ; N afii10052 ; B 62 0 606 922 ;
-C -1 ; WX 592 ; N afii10053 ; B 88 -19 648 737 ;
-C -1 ; WX 547 ; N afii10054 ; B 66 -19 588 737 ;
-C -1 ; WX 228 ; N afii10055 ; B 52 0 301 718 ;
-C -1 ; WX 228 ; N afii10056 ; B 52 0 405 915 ;
-C -1 ; WX 456 ; N afii10057 ; B 49 -18 522 718 ;
-C -1 ; WX 838 ; N afii10058 ; B -48 0 850 718 ;
-C -1 ; WX 874 ; N afii10059 ; B 58 0 908 718 ;
-C -1 ; WX 650 ; N afii10060 ; B 114 0 657 718 ;
-C -1 ; WX 593 ; N afii10061 ; B 71 0 704 922 ;
-C -1 ; WX 596 ; N uni040D ; B 58 0 663 964 ;
-C -1 ; WX 547 ; N afii10062 ; B 86 0 661 936 ;
-C -1 ; WX 590 ; N afii10145 ; B 57 -120 659 718 ;
-C -1 ; WX 456 ; N uni0450 ; B 58 -14 486 778 ;
-C -1 ; WX 518 ; N afii10099 ; B 95 -135 541 718 ;
-C -1 ; WX 380 ; N afii10100 ; B 50 0 462 740 ;
-C -1 ; WX 456 ; N afii10101 ; B 64 -14 492 546 ;
-C -1 ; WX 456 ; N afii10102 ; B 52 -14 479 546 ;
-C -1 ; WX 228 ; N afii10103 ; B 57 0 298 725 ;
-C -1 ; WX 228 ; N afii10104 ; B 57 0 376 747 ;
-C -1 ; WX 228 ; N afii10105 ; B -35 -214 298 725 ;
-C -1 ; WX 730 ; N afii10106 ; B -29 0 733 532 ;
-C -1 ; WX 739 ; N afii10107 ; B 53 0 779 532 ;
-C -1 ; WX 518 ; N afii10108 ; B 95 0 541 718 ;
-C -1 ; WX 457 ; N afii10109 ; B 57 0 550 740 ;
-C -1 ; WX 503 ; N uni045D ; B 53 0 542 778 ;
-C -1 ; WX 456 ; N afii10110 ; B 34 -214 535 750 ;
-C -1 ; WX 503 ; N afii10193 ; B 53 -120 542 532 ;
-C -1 ; WX 584 ; N uni048C ; B 122 0 619 718 ;
-C -1 ; WX 508 ; N uni048D ; B 90 0 547 532 ;
-C -1 ; WX 583 ; N uni048E ; B 62 0 616 718 ;
-C -1 ; WX 541 ; N uni048F ; B 15 -207 536 546 ;
-C -1 ; WX 541 ; N afii10050 ; B 62 0 625 822 ;
-C -1 ; WX 424 ; N afii10098 ; B 50 0 480 640 ;
-C -1 ; WX 501 ; N uni0492 ; B 62 0 606 718 ;
-C -1 ; WX 380 ; N uni0493 ; B 46 0 462 532 ;
-C -1 ; WX 574 ; N uni0494 ; B 62 -138 606 718 ;
-C -1 ; WX 491 ; N uni0495 ; B 50 -135 474 532 ;
-C -1 ; WX 900 ; N uni0496 ; B 11 -120 1001 718 ;
-C -1 ; WX 720 ; N uni0497 ; B 12 -120 795 532 ;
-C -1 ; WX 537 ; N uni0498 ; B 54 -228 581 737 ;
-C -1 ; WX 457 ; N uni0499 ; B 53 -228 482 546 ;
-C -1 ; WX 593 ; N uni049A ; B 71 -120 704 718 ;
-C -1 ; WX 457 ; N uni049B ; B 57 -120 550 532 ;
-C -1 ; WX 593 ; N uni049C ; B 71 0 704 718 ;
-C -1 ; WX 457 ; N uni049D ; B 57 0 550 532 ;
-C -1 ; WX 593 ; N uni049E ; B 71 0 704 718 ;
-C -1 ; WX 457 ; N uni049F ; B 57 0 550 532 ;
-C -1 ; WX 694 ; N uni04A0 ; B 57 0 805 718 ;
-C -1 ; WX 535 ; N uni04A1 ; B 82 0 627 532 ;
-C -1 ; WX 592 ; N uni04A2 ; B 58 -120 659 718 ;
-C -1 ; WX 503 ; N uni04A3 ; B 53 -120 561 532 ;
-C -1 ; WX 830 ; N uni04A4 ; B 58 0 935 718 ;
-C -1 ; WX 709 ; N uni04A5 ; B 53 0 741 532 ;
-C -1 ; WX 920 ; N uni04A6 ; B 57 -138 920 718 ;
-C -1 ; WX 788 ; N uni04A7 ; B 53 -135 759 532 ;
-C -1 ; WX 592 ; N uni04A8 ; B 88 -22 647 737 ;
-C -1 ; WX 456 ; N uni04A9 ; B 65 -20 491 546 ;
-C -1 ; WX 592 ; N uni04AA ; B 88 -228 647 737 ;
-C -1 ; WX 456 ; N uni04AB ; B 65 -228 491 546 ;
-C -1 ; WX 501 ; N uni04AC ; B 114 -120 615 718 ;
-C -1 ; WX 370 ; N uni04AD ; B 82 -120 452 532 ;
-C -1 ; WX 547 ; N uni04AE ; B 137 0 661 718 ;
-C -1 ; WX 547 ; N uni04AF ; B 105 -186 629 532 ;
-C -1 ; WX 547 ; N uni04B0 ; B 84 0 661 718 ;
-C -1 ; WX 547 ; N uni04B1 ; B 60 -186 629 532 ;
-C -1 ; WX 547 ; N uni04B2 ; B 11 -120 648 718 ;
-C -1 ; WX 456 ; N uni04B3 ; B 12 -120 531 532 ;
-C -1 ; WX 758 ; N uni04B4 ; B 114 -120 781 718 ;
-C -1 ; WX 634 ; N uni04B5 ; B 82 -120 644 532 ;
-C -1 ; WX 549 ; N uni04B6 ; B 53 -120 572 718 ;
-C -1 ; WX 487 ; N uni04B7 ; B 48 -120 497 532 ;
-C -1 ; WX 492 ; N uni04B8 ; B 53 0 561 718 ;
-C -1 ; WX 418 ; N uni04B9 ; B 48 0 458 532 ;
-C -1 ; WX 492 ; N uni04BA ; B 53 0 561 718 ;
-C -1 ; WX 418 ; N uni04BB ; B 48 0 458 532 ;
-C -1 ; WX 842 ; N uni04BC ; B 102 -19 879 737 ;
-C -1 ; WX 691 ; N uni04BD ; B 87 -14 717 546 ;
-C -1 ; WX 842 ; N uni04BE ; B 102 -228 879 737 ;
-C -1 ; WX 691 ; N uni04BF ; B 87 -228 717 546 ;
-C -1 ; WX 228 ; N uni04C0 ; B 52 0 301 718 ;
-C -1 ; WX 900 ; N uni04C1 ; B 11 0 1001 964 ;
-C -1 ; WX 720 ; N uni04C2 ; B 12 0 795 778 ;
-C -1 ; WX 593 ; N uni04C3 ; B 71 -138 704 718 ;
-C -1 ; WX 477 ; N uni04C4 ; B 57 -143 550 532 ;
-C -1 ; WX 592 ; N uni04C7 ; B 58 -138 659 718 ;
-C -1 ; WX 503 ; N uni04C8 ; B 53 -135 542 532 ;
-C -1 ; WX 492 ; N uni04CB ; B 53 -120 561 718 ;
-C -1 ; WX 418 ; N uni04CC ; B 48 -120 458 532 ;
-C -1 ; WX 592 ; N uni04D0 ; B 16 0 602 964 ;
-C -1 ; WX 456 ; N uni04D1 ; B 45 -14 504 778 ;
-C -1 ; WX 592 ; N uni04D2 ; B 16 0 590 933 ;
-C -1 ; WX 456 ; N uni04D3 ; B 45 -14 492 747 ;
-C -1 ; WX 820 ; N uni04D4 ; B 4 0 902 718 ;
-C -1 ; WX 729 ; N uni04D5 ; B 46 -14 757 546 ;
-C -1 ; WX 547 ; N uni04D6 ; B 62 0 620 964 ;
-C -1 ; WX 456 ; N uni04D7 ; B 58 -14 504 778 ;
-C -1 ; WX 638 ; N uni04D8 ; B 88 -19 675 737 ;
-C -1 ; WX 501 ; N afii10846 ; B 67 -14 527 546 ;
-C -1 ; WX 638 ; N uni04DA ; B 88 -19 675 872 ;
-C -1 ; WX 501 ; N uni04DB ; B 67 -14 527 681 ;
-C -1 ; WX 900 ; N uni04DC ; B 11 0 1001 933 ;
-C -1 ; WX 720 ; N uni04DD ; B 12 0 795 747 ;
-C -1 ; WX 537 ; N uni04DE ; B 54 -19 581 872 ;
-C -1 ; WX 457 ; N uni04DF ; B 53 -14 484 681 ;
-C -1 ; WX 537 ; N uni04E0 ; B 54 -19 651 718 ;
-C -1 ; WX 457 ; N uni04E1 ; B 53 -14 538 532 ;
-C -1 ; WX 596 ; N uni04E2 ; B 58 0 663 892 ;
-C -1 ; WX 503 ; N uni04E3 ; B 53 0 542 706 ;
-C -1 ; WX 596 ; N uni04E4 ; B 58 0 663 933 ;
-C -1 ; WX 503 ; N uni04E5 ; B 53 0 542 747 ;
-C -1 ; WX 638 ; N uni04E6 ; B 88 -19 675 933 ;
-C -1 ; WX 501 ; N uni04E7 ; B 67 -14 527 747 ;
-C -1 ; WX 638 ; N uni04E8 ; B 88 -19 675 737 ;
-C -1 ; WX 501 ; N uni04E9 ; B 67 -14 527 546 ;
-C -1 ; WX 638 ; N uni04EA ; B 88 -19 675 872 ;
-C -1 ; WX 501 ; N uni04EB ; B 67 -14 527 681 ;
-C -1 ; WX 606 ; N uni04EC ; B 88 -19 644 933 ;
-C -1 ; WX 462 ; N uni04ED ; B 66 -14 496 747 ;
-C -1 ; WX 547 ; N uni04EE ; B 86 0 661 892 ;
-C -1 ; WX 456 ; N uni04EF ; B 34 -214 535 706 ;
-C -1 ; WX 547 ; N uni04F0 ; B 86 0 661 933 ;
-C -1 ; WX 456 ; N uni04F1 ; B 34 -214 535 747 ;
-C -1 ; WX 547 ; N uni04F2 ; B 86 0 661 964 ;
-C -1 ; WX 456 ; N uni04F3 ; B 34 -214 556 778 ;
-C -1 ; WX 492 ; N uni04F4 ; B 53 0 561 912 ;
-C -1 ; WX 418 ; N uni04F5 ; B 48 0 458 721 ;
-C -1 ; WX 727 ; N uni04F8 ; B 62 0 796 933 ;
-C -1 ; WX 687 ; N uni04F9 ; B 53 0 726 747 ;
-C -1 ; WX 380 ; N uniF6C4 ; B 50 0 462 532 ;
-C -1 ; WX 501 ; N uniF6C5 ; B 1 -14 552 776 ;
-C -1 ; WX 637 ; N uniF6C6 ; B -27 -120 593 532 ;
-C -1 ; WX 503 ; N uniF6C7 ; B 53 0 542 532 ;
-C -1 ; WX 370 ; N uniF6C8 ; B 82 0 452 532 ;
-C -1 ; WX 592 ; N Ccircumflex ; B 88 -19 647 964 ;
-C -1 ; WX 456 ; N ccircumflex ; B 65 -14 491 778 ;
-C -1 ; WX 592 ; N Cdotaccent ; B 88 -19 647 933 ;
-C -1 ; WX 456 ; N cdotaccent ; B 65 -14 491 747 ;
-C -1 ; WX 547 ; N Ebreve ; B 62 0 620 964 ;
-C -1 ; WX 456 ; N ebreve ; B 58 -14 504 778 ;
-C -1 ; WX 638 ; N Gcircumflex ; B 89 -19 670 964 ;
-C -1 ; WX 501 ; N gcircumflex ; B 31 -217 546 778 ;
-C -1 ; WX 638 ; N Gdotaccent ; B 89 -19 670 933 ;
-C -1 ; WX 501 ; N gdotaccent ; B 31 -217 546 747 ;
-C -1 ; WX 592 ; N Hcircumflex ; B 58 0 659 964 ;
-C -1 ; WX 501 ; N hcircumflex ; B 53 0 538 964 ;
-C -1 ; WX 678 ; N Hbar ; B 103 0 765 718 ;
-C -1 ; WX 541 ; N hbar ; B 93 0 556 718 ;
-C -1 ; WX 228 ; N Itilde ; B 52 0 429 945 ;
-C -1 ; WX 228 ; N itilde ; B 57 0 397 759 ;
-C -1 ; WX 228 ; N Ibreve ; B 52 0 420 964 ;
-C -1 ; WX 228 ; N ibreve ; B 57 0 388 778 ;
-C -1 ; WX 650 ; N IJ ; B 52 -18 722 718 ;
-C -1 ; WX 432 ; N ij ; B 57 -214 498 725 ;
-C -1 ; WX 456 ; N Jcircumflex ; B 49 -18 522 964 ;
-C -1 ; WX 228 ; N jcircumflex ; B -35 -214 387 750 ;
-C -1 ; WX 457 ; N kgreenlandic ; B 57 0 550 532 ;
-C -1 ; WX 501 ; N Ldot ; B 62 0 501 718 ;
-C -1 ; WX 456 ; N ldot ; B 57 0 454 718 ;
-C -1 ; WX 501 ; N napostrophe ; B 53 0 516 858 ;
-C -1 ; WX 592 ; N Eng ; B 57 -138 661 718 ;
-C -1 ; WX 501 ; N eng ; B 53 -135 516 546 ;
-C -1 ; WX 638 ; N Obreve ; B 88 -19 675 964 ;
-C -1 ; WX 501 ; N obreve ; B 67 -14 527 778 ;
-C -1 ; WX 547 ; N Scircumflex ; B 66 -19 588 964 ;
-C -1 ; WX 456 ; N scircumflex ; B 52 -14 480 778 ;
-C -1 ; WX 501 ; N Tbar ; B 97 0 615 718 ;
-C -1 ; WX 273 ; N tbar ; B 59 -6 346 676 ;
-C -1 ; WX 592 ; N Utilde ; B 96 -19 659 945 ;
-C -1 ; WX 501 ; N utilde ; B 80 -14 540 759 ;
-C -1 ; WX 592 ; N Ubreve ; B 96 -19 659 964 ;
-C -1 ; WX 501 ; N ubreve ; B 80 -14 540 778 ;
-C -1 ; WX 774 ; N Wcircumflex ; B 138 0 887 964 ;
-C -1 ; WX 638 ; N wcircumflex ; B 101 0 723 778 ;
-C -1 ; WX 547 ; N Ycircumflex ; B 137 0 661 964 ;
-C -1 ; WX 456 ; N ycircumflex ; B 34 -214 535 778 ;
-C -1 ; WX 273 ; N longs ; B 71 0 385 727 ;
-C -1 ; WX 867 ; N afii61352 ; B 57 0 905 718 ;
-C -1 ; WX 702 ; N infinity ; B 81 162 741 529 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 981
-KPX quoteright A -59
-KPX quoteright AE -55
-KPX quoteright Aacute -59
-KPX quoteright Adieresis -59
-KPX quoteright Aring -59
-KPX quoteright comma -35
-KPX quoteright d -23
-KPX quoteright o -28
-KPX quoteright period -35
-KPX quoteright r -11
-KPX quoteright s -21
-KPX quoteright v -3
-KPX quoteright y -2
-KPX comma one -65
-KPX comma quotedblright -27
-KPX comma quoteright -29
-KPX hyphen AE 6
-KPX hyphen T -46
-KPX hyphen V -19
-KPX hyphen W -8
-KPX hyphen Y -52
-KPX period one -65
-KPX period quotedblright -27
-KPX period quoteright -29
-KPX zero four 2
-KPX zero one -20
-KPX zero seven -11
-KPX one comma -39
-KPX one eight -41
-KPX one five -41
-KPX one four -57
-KPX one nine -42
-KPX one one -74
-KPX one period -39
-KPX one seven -55
-KPX one six -39
-KPX one three -46
-KPX one two -47
-KPX one zero -39
-KPX two four -21
-KPX two one -21
-KPX two seven -10
-KPX three four -1
-KPX three one -27
-KPX three seven -13
-KPX four four 3
-KPX four one -46
-KPX four seven -27
-KPX five one -30
-KPX five seven -10
-KPX six one -23
-KPX six seven -9
-KPX seven colon -48
-KPX seven comma -77
-KPX seven eight -11
-KPX seven five -20
-KPX seven four -59
-KPX seven one -14
-KPX seven period -77
-KPX seven seven 5
-KPX seven six -16
-KPX seven three -9
-KPX seven two -8
-KPX eight four 2
-KPX eight one -24
-KPX eight seven -10
-KPX nine one -21
-KPX nine seven -14
-KPX A C -30
-KPX A Ccedilla -30
-KPX A G -31
-KPX A O -31
-KPX A Odieresis -31
-KPX A Q -30
-KPX A T -72
-KPX A U -29
-KPX A Uacute -29
-KPX A Ucircumflex -29
-KPX A Udieresis -29
-KPX A Ugrave -29
-KPX A V -56
-KPX A W -46
-KPX A Y -75
-KPX A a -11
-KPX A b -11
-KPX A c -15
-KPX A ccedilla -14
-KPX A comma 9
-KPX A d -14
-KPX A e -11
-KPX A g -19
-KPX A guillemotleft -41
-KPX A guilsinglleft -39
-KPX A hyphen 1
-KPX A o -17
-KPX A period 11
-KPX A q -14
-KPX A quotedblright -54
-KPX A quoteright -56
-KPX A t -16
-KPX A u -16
-KPX A v -34
-KPX A w -24
-KPX A y -32
-KPX B A -27
-KPX B AE -21
-KPX B Aacute -27
-KPX B Acircumflex -27
-KPX B Adieresis -27
-KPX B Aring -27
-KPX B Atilde -27
-KPX B O -12
-KPX B OE -6
-KPX B Oacute -12
-KPX B Ocircumflex -12
-KPX B Odieresis -12
-KPX B Ograve -12
-KPX B Oslash -9
-KPX B V -31
-KPX B W -21
-KPX B Y -40
-KPX C A -29
-KPX C AE -23
-KPX C Aacute -29
-KPX C Adieresis -29
-KPX C Aring -29
-KPX C H -7
-KPX C K -13
-KPX C O -12
-KPX C Oacute -12
-KPX C Odieresis -12
-KPX D A -31
-KPX D Aacute -31
-KPX D Acircumflex -31
-KPX D Adieresis -31
-KPX D Agrave -31
-KPX D Aring -31
-KPX D Atilde -31
-KPX D J -1
-KPX D T -14
-KPX D V -25
-KPX D W -16
-KPX D X -28
-KPX D Y -43
-KPX F A -53
-KPX F Aacute -53
-KPX F Acircumflex -53
-KPX F Adieresis -53
-KPX F Agrave -53
-KPX F Aring -53
-KPX F Atilde -53
-KPX F J -24
-KPX F O -19
-KPX F Odieresis -19
-KPX F a -24
-KPX F aacute -24
-KPX F adieresis -24
-KPX F ae -24
-KPX F aring -24
-KPX F comma -78
-KPX F e -15
-KPX F eacute -15
-KPX F i -14
-KPX F j -13
-KPX F o -19
-KPX F oacute -19
-KPX F odieresis -19
-KPX F oe -19
-KPX F oslash -20
-KPX F period -77
-KPX F r -30
-KPX F u -31
-KPX G A -8
-KPX G AE -2
-KPX G Aacute -8
-KPX G Acircumflex -8
-KPX G Adieresis -8
-KPX G Agrave -8
-KPX G Aring -8
-KPX G Atilde -8
-KPX G T -18
-KPX G V -29
-KPX G W -20
-KPX G Y -47
-KPX J A -30
-KPX J AE -25
-KPX J Adieresis -30
-KPX J Aring -30
-KPX K C -42
-KPX K G -43
-KPX K O -43
-KPX K OE -37
-KPX K Oacute -43
-KPX K Odieresis -43
-KPX K S -30
-KPX K T 14
-KPX K a -10
-KPX K adieresis -10
-KPX K ae -11
-KPX K aring -10
-KPX K e -27
-KPX K hyphen -34
-KPX K o -35
-KPX K oacute -35
-KPX K odieresis -35
-KPX K u -30
-KPX K udieresis -30
-KPX K y -57
-KPX L A 6
-KPX L AE 12
-KPX L Aacute 6
-KPX L Adieresis 6
-KPX L Aring 6
-KPX L C -25
-KPX L Ccedilla -26
-KPX L G -27
-KPX L O -26
-KPX L Oacute -26
-KPX L Ocircumflex -26
-KPX L Odieresis -26
-KPX L Ograve -26
-KPX L Otilde -26
-KPX L S -8
-KPX L T -79
-KPX L U -23
-KPX L Udieresis -23
-KPX L V -75
-KPX L W -60
-KPX L Y -92
-KPX L hyphen -19
-KPX L quotedblright -123
-KPX L quoteright -125
-KPX L u -17
-KPX L udieresis -17
-KPX L y -50
-KPX N A -10
-KPX N AE -4
-KPX N Aacute -10
-KPX N Adieresis -10
-KPX N Aring -10
-KPX N C -3
-KPX N Ccedilla -2
-KPX N G -4
-KPX N O -4
-KPX N Oacute -4
-KPX N Odieresis -4
-KPX N a -1
-KPX N aacute -1
-KPX N adieresis -1
-KPX N ae -2
-KPX N aring -1
-KPX N comma 5
-KPX N e 2
-KPX N eacute 2
-KPX N o -3
-KPX N oacute -3
-KPX N odieresis -3
-KPX N period 5
-KPX N u -1
-KPX N udieresis -2
-KPX O A -35
-KPX O AE -30
-KPX O Aacute -35
-KPX O Adieresis -35
-KPX O Aring -35
-KPX O T -21
-KPX O V -29
-KPX O W -20
-KPX O X -32
-KPX O Y -50
-KPX P A -61
-KPX P AE -56
-KPX P Aacute -61
-KPX P Adieresis -61
-KPX P Aring -61
-KPX P J -45
-KPX P a -22
-KPX P aacute -22
-KPX P adieresis -22
-KPX P ae -22
-KPX P aring -22
-KPX P comma -98
-KPX P e -20
-KPX P eacute -20
-KPX P hyphen -13
-KPX P o -24
-KPX P oacute -24
-KPX P odieresis -24
-KPX P oe -25
-KPX P oslash -25
-KPX P period -98
-KPX R C -10
-KPX R Ccedilla -9
-KPX R G -11
-KPX R O -11
-KPX R OE -5
-KPX R Oacute -11
-KPX R Odieresis -11
-KPX R T -9
-KPX R U -9
-KPX R Udieresis -9
-KPX R V -27
-KPX R W -18
-KPX R Y -36
-KPX R a -7
-KPX R aacute -7
-KPX R adieresis -7
-KPX R ae -7
-KPX R aring -7
-KPX R e -4
-KPX R eacute -4
-KPX R hyphen 7
-KPX R o -10
-KPX R oacute -10
-KPX R odieresis -10
-KPX R oe -10
-KPX R u -7
-KPX R uacute -8
-KPX R udieresis -8
-KPX R y -6
-KPX S A -20
-KPX S AE -14
-KPX S Aacute -20
-KPX S Adieresis -20
-KPX S Aring -20
-KPX S T -12
-KPX S V -29
-KPX S W -20
-KPX S Y -39
-KPX S t -5
-KPX T A -72
-KPX T AE -68
-KPX T Aacute -72
-KPX T Acircumflex -72
-KPX T Adieresis -72
-KPX T Agrave -72
-KPX T Aring -72
-KPX T Atilde -72
-KPX T C -18
-KPX T G -19
-KPX T J -77
-KPX T O -18
-KPX T OE -12
-KPX T Oacute -18
-KPX T Ocircumflex -18
-KPX T Odieresis -18
-KPX T Ograve -18
-KPX T Oslash -18
-KPX T Otilde -18
-KPX T S -3
-KPX T V 11
-KPX T W 13
-KPX T Y 13
-KPX T a -68
-KPX T ae -69
-KPX T c -68
-KPX T colon -79
-KPX T comma -61
-KPX T e -64
-KPX T g -69
-KPX T guillemotleft -92
-KPX T guilsinglleft -89
-KPX T hyphen -46
-KPX T i -9
-KPX T j -9
-KPX T o -70
-KPX T oslash -67
-KPX T period -61
-KPX T r -64
-KPX T s -69
-KPX T semicolon -79
-KPX T u -68
-KPX T v -77
-KPX T w -72
-KPX T y -76
-KPX U A -32
-KPX U AE -27
-KPX U Aacute -32
-KPX U Acircumflex -32
-KPX U Adieresis -32
-KPX U Aring -32
-KPX U Atilde -32
-KPX U comma -14
-KPX U m -5
-KPX U n -5
-KPX U p -5
-KPX U period -11
-KPX U r -5
-KPX V A -58
-KPX V AE -53
-KPX V Aacute -58
-KPX V Acircumflex -58
-KPX V Adieresis -58
-KPX V Agrave -58
-KPX V Aring -58
-KPX V Atilde -58
-KPX V C -33
-KPX V G -34
-KPX V O -34
-KPX V Oacute -34
-KPX V Ocircumflex -34
-KPX V Odieresis -34
-KPX V Ograve -34
-KPX V Oslash -29
-KPX V Otilde -34
-KPX V S -23
-KPX V T 13
-KPX V a -45
-KPX V ae -46
-KPX V colon -47
-KPX V comma -58
-KPX V e -41
-KPX V g -45
-KPX V guillemotleft -68
-KPX V guilsinglleft -65
-KPX V hyphen -22
-KPX V i -12
-KPX V o -47
-KPX V oslash -44
-KPX V period -58
-KPX V r -36
-KPX V semicolon -47
-KPX V u -40
-KPX V y -17
-KPX W A -47
-KPX W AE -42
-KPX W Aacute -47
-KPX W Acircumflex -47
-KPX W Adieresis -47
-KPX W Agrave -47
-KPX W Aring -47
-KPX W Atilde -47
-KPX W C -23
-KPX W G -24
-KPX W O -23
-KPX W Oacute -23
-KPX W Ocircumflex -23
-KPX W Odieresis -23
-KPX W Ograve -23
-KPX W Oslash -19
-KPX W Otilde -23
-KPX W S -18
-KPX W T 15
-KPX W a -32
-KPX W ae -33
-KPX W colon -40
-KPX W comma -42
-KPX W e -28
-KPX W g -32
-KPX W guillemotleft -55
-KPX W guilsinglleft -52
-KPX W hyphen -9
-KPX W i -10
-KPX W o -34
-KPX W oslash -31
-KPX W period -42
-KPX W r -27
-KPX W semicolon -41
-KPX W u -32
-KPX W y -11
-KPX X C -32
-KPX X O -33
-KPX X Odieresis -33
-KPX X Q -33
-KPX X a -15
-KPX X e -31
-KPX X hyphen -28
-KPX X o -37
-KPX X u -34
-KPX X y -44
-KPX Y A -73
-KPX Y AE -68
-KPX Y Aacute -73
-KPX Y Acircumflex -73
-KPX Y Adieresis -73
-KPX Y Agrave -73
-KPX Y Aring -73
-KPX Y Atilde -73
-KPX Y C -45
-KPX Y G -46
-KPX Y O -46
-KPX Y Oacute -46
-KPX Y Ocircumflex -46
-KPX Y Odieresis -46
-KPX Y Ograve -46
-KPX Y Oslash -45
-KPX Y Otilde -46
-KPX Y S -28
-KPX Y T 16
-KPX Y a -64
-KPX Y ae -65
-KPX Y colon -61
-KPX Y comma -71
-KPX Y e -60
-KPX Y g -64
-KPX Y guillemotleft -91
-KPX Y guilsinglleft -88
-KPX Y hyphen -49
-KPX Y i -9
-KPX Y o -66
-KPX Y oslash -63
-KPX Y p -48
-KPX Y period -71
-KPX Y semicolon -61
-KPX Y u -54
-KPX Y v -31
-KPX Z v -19
-KPX Z y -18
-KPX quoteleft A -57
-KPX quoteleft AE -53
-KPX quoteleft Aacute -57
-KPX quoteleft Adieresis -57
-KPX quoteleft Aring -57
-KPX quoteleft T -8
-KPX quoteleft V 2
-KPX quoteleft W 7
-KPX quoteleft Y -8
-KPX a j -2
-KPX a quoteright -11
-KPX a v -16
-KPX a w -7
-KPX a y -16
-KPX b v -15
-KPX b w -6
-KPX b y -17
-KPX c h -6
-KPX c k -8
-KPX e quoteright -11
-KPX e t -4
-KPX e v -16
-KPX e w -6
-KPX e x -19
-KPX e y -17
-KPX f a -12
-KPX f aacute -12
-KPX f adieresis -12
-KPX f ae -13
-KPX f aring -12
-KPX f e -10
-KPX f eacute -10
-KPX f f 12
-KPX f i -11
-KPX f j -11
-KPX f l -11
-KPX f o -16
-KPX f oacute -16
-KPX f odieresis -16
-KPX f oe -16
-KPX f oslash -13
-KPX f s -13
-KPX f t 12
-KPX g a -2
-KPX g adieresis -2
-KPX g ae -3
-KPX g aring -2
-KPX g e 1
-KPX g eacute 1
-KPX g oacute -4
-KPX g odieresis -4
-KPX g r 1
-KPX h quoteright -13
-KPX h y -18
-KPX i T -9
-KPX i j -3
-KPX k a -9
-KPX k aacute -9
-KPX k adieresis -9
-KPX k ae -9
-KPX k aring -9
-KPX k comma 7
-KPX k e -11
-KPX k eacute -11
-KPX k g -16
-KPX k hyphen -16
-KPX k o -18
-KPX k oacute -18
-KPX k odieresis -18
-KPX k period 7
-KPX k s -15
-KPX k u -12
-KPX k udieresis -6
-KPX l v -14
-KPX l y -13
-KPX m p -1
-KPX m v -17
-KPX m w -8
-KPX m y -17
-KPX n T -67
-KPX n p -2
-KPX n quoteright -12
-KPX n v -18
-KPX n w -9
-KPX n y -18
-KPX o T -68
-KPX o quoteright -16
-KPX o t -7
-KPX o v -19
-KPX o w -9
-KPX o x -22
-KPX o y -21
-KPX p t -4
-KPX p y -18
-KPX q c -1
-KPX q u -2
-KPX r a -9
-KPX r aacute -9
-KPX r acircumflex -9
-KPX r adieresis -9
-KPX r ae -9
-KPX r agrave -9
-KPX r aring -9
-KPX r c -11
-KPX r ccedilla -7
-KPX r colon -19
-KPX r comma -47
-KPX r d -9
-KPX r e -8
-KPX r eacute -8
-KPX r ecircumflex -8
-KPX r egrave -8
-KPX r f 12
-KPX r g -6
-KPX r h -10
-KPX r hyphen -30
-KPX r i -13
-KPX r j -12
-KPX r k -12
-KPX r l -12
-KPX r m -10
-KPX r n -11
-KPX r o -12
-KPX r oacute -12
-KPX r ocircumflex -12
-KPX r odieresis -12
-KPX r oe -12
-KPX r ograve -12
-KPX r oslash -13
-KPX r p -10
-KPX r period -47
-KPX r q -9
-KPX r quoteright 4
-KPX r r -10
-KPX r s -8
-KPX r semicolon -19
-KPX r t 12
-KPX r u -12
-KPX r v 8
-KPX r w 10
-KPX r x 4
-KPX r y 9
-KPX s quoteright -12
-KPX s t -7
-KPX t S -5
-KPX t a -3
-KPX t aacute -3
-KPX t adieresis -3
-KPX t ae -3
-KPX t aring -3
-KPX t colon -19
-KPX t e -6
-KPX t eacute -6
-KPX t h -4
-KPX t o -12
-KPX t oacute -12
-KPX t odieresis -12
-KPX t quoteright -1
-KPX t semicolon -19
-KPX u quoteright -4
-KPX v a -21
-KPX v aacute -21
-KPX v acircumflex -21
-KPX v adieresis -21
-KPX v ae -22
-KPX v agrave -21
-KPX v aring -21
-KPX v atilde -21
-KPX v c -20
-KPX v colon -20
-KPX v comma -40
-KPX v e -17
-KPX v eacute -17
-KPX v ecircumflex -17
-KPX v egrave -17
-KPX v g -20
-KPX v l -12
-KPX v o -23
-KPX v oacute -23
-KPX v odieresis -23
-KPX v ograve -23
-KPX v oslash -20
-KPX v period -39
-KPX v s -21
-KPX v semicolon -20
-KPX w a -12
-KPX w aacute -12
-KPX w acircumflex -12
-KPX w adieresis -12
-KPX w ae -13
-KPX w agrave -12
-KPX w aring -12
-KPX w atilde -12
-KPX w c -11
-KPX w colon -18
-KPX w comma -25
-KPX w e -7
-KPX w eacute -7
-KPX w ecircumflex -7
-KPX w egrave -7
-KPX w g -11
-KPX w hyphen 9
-KPX w l -9
-KPX w o -13
-KPX w oacute -13
-KPX w odieresis -13
-KPX w ograve -13
-KPX w oslash -11
-KPX w period -25
-KPX w s -12
-KPX w semicolon -18
-KPX x a -19
-KPX x c -22
-KPX x e -18
-KPX x eacute -18
-KPX x o -24
-KPX x q -20
-KPX y a -23
-KPX y aacute -23
-KPX y acircumflex -23
-KPX y adieresis -23
-KPX y ae -23
-KPX y agrave -23
-KPX y aring -23
-KPX y atilde -23
-KPX y c -22
-KPX y colon -21
-KPX y comma -40
-KPX y e -19
-KPX y eacute -19
-KPX y ecircumflex -19
-KPX y egrave -19
-KPX y g -23
-KPX y l -14
-KPX y o -25
-KPX y oacute -25
-KPX y odieresis -25
-KPX y ograve -25
-KPX y oslash -21
-KPX y period -40
-KPX y s -23
-KPX y semicolon -22
-KPX quotedblleft A -55
-KPX quotedblleft AE -51
-KPX quotedblleft Aacute -55
-KPX quotedblleft Adieresis -55
-KPX quotedblleft Aring -55
-KPX quotedblleft T -6
-KPX quotedblleft V 4
-KPX quotedblleft W 9
-KPX quotedblleft Y -6
-KPX guilsinglright A -40
-KPX guilsinglright AE -35
-KPX guilsinglright Aacute -40
-KPX guilsinglright Adieresis -40
-KPX guilsinglright Aring -40
-KPX guilsinglright T -88
-KPX guilsinglright V -61
-KPX guilsinglright W -49
-KPX guilsinglright Y -90
-KPX quotedblbase A 9
-KPX quotedblbase AE 15
-KPX quotedblbase T -61
-KPX quotedblbase V -58
-KPX quotedblbase W -43
-KPX quotedblbase Y -75
-KPX quotedblright A -57
-KPX quotedblright AE -53
-KPX quotedblright Aacute -57
-KPX quotedblright Adieresis -57
-KPX quotedblright Aring -57
-KPX quotedblright T -4
-KPX quotedblright V 2
-KPX quotedblright W 7
-KPX quotedblright Y -8
-KPX guillemotright A -42
-KPX guillemotright AE -36
-KPX guillemotright Aacute -42
-KPX guillemotright Adieresis -42
-KPX guillemotright Aring -42
-KPX guillemotright T -89
-KPX guillemotright V -63
-KPX guillemotright W -51
-KPX guillemotright Y -92
-KPX Oslash A -32
-KPX ae v -17
-KPX ae w -7
-KPX ae y -18
-KPX Adieresis C -31
-KPX Adieresis G -32
-KPX Adieresis O -32
-KPX Adieresis Q -31
-KPX Adieresis T -72
-KPX Adieresis U -30
-KPX Adieresis V -56
-KPX Adieresis W -46
-KPX Adieresis Y -75
-KPX Adieresis a -11
-KPX Adieresis b -11
-KPX Adieresis c -15
-KPX Adieresis comma 9
-KPX Adieresis d -15
-KPX Adieresis g -19
-KPX Adieresis guillemotleft -42
-KPX Adieresis guilsinglleft -39
-KPX Adieresis o -18
-KPX Adieresis period 10
-KPX Adieresis q -15
-KPX Adieresis quotedblright -54
-KPX Adieresis quoteright -57
-KPX Adieresis t -16
-KPX Adieresis u -16
-KPX Adieresis v -34
-KPX Adieresis w -24
-KPX Adieresis y -32
-KPX Aacute C -31
-KPX Aacute G -32
-KPX Aacute O -32
-KPX Aacute Q -32
-KPX Aacute T -72
-KPX Aacute U -30
-KPX Aacute V -56
-KPX Aacute W -46
-KPX Aacute Y -74
-KPX Aacute a -11
-KPX Aacute b -11
-KPX Aacute c -16
-KPX Aacute comma 9
-KPX Aacute d -16
-KPX Aacute e -12
-KPX Aacute g -19
-KPX Aacute guillemotleft -42
-KPX Aacute guilsinglleft -40
-KPX Aacute hyphen 1
-KPX Aacute o -18
-KPX Aacute period 9
-KPX Aacute q -15
-KPX Aacute quoteright -56
-KPX Aacute t -17
-KPX Aacute u -17
-KPX Aacute v -33
-KPX Aacute w -24
-KPX Aacute y -32
-KPX Agrave C -30
-KPX Agrave G -31
-KPX Agrave O -31
-KPX Agrave Q -30
-KPX Agrave T -72
-KPX Agrave U -29
-KPX Agrave V -56
-KPX Agrave W -46
-KPX Agrave Y -75
-KPX Agrave comma 9
-KPX Agrave period 11
-KPX Acircumflex C -30
-KPX Acircumflex G -31
-KPX Acircumflex O -31
-KPX Acircumflex Q -30
-KPX Acircumflex T -72
-KPX Acircumflex U -29
-KPX Acircumflex V -56
-KPX Acircumflex W -46
-KPX Acircumflex Y -74
-KPX Acircumflex comma 10
-KPX Acircumflex period 11
-KPX Atilde C -32
-KPX Atilde G -33
-KPX Atilde O -33
-KPX Atilde Q -32
-KPX Atilde T -73
-KPX Atilde U -31
-KPX Atilde V -56
-KPX Atilde W -47
-KPX Atilde Y -75
-KPX Atilde comma 9
-KPX Atilde period 9
-KPX Aring C -30
-KPX Aring G -31
-KPX Aring O -31
-KPX Aring Q -30
-KPX Aring T -72
-KPX Aring U -29
-KPX Aring V -56
-KPX Aring W -46
-KPX Aring Y -75
-KPX Aring a -11
-KPX Aring b -11
-KPX Aring c -15
-KPX Aring comma 9
-KPX Aring d -14
-KPX Aring e -11
-KPX Aring g -19
-KPX Aring guillemotleft -41
-KPX Aring guilsinglleft -39
-KPX Aring hyphen 1
-KPX Aring o -17
-KPX Aring period 11
-KPX Aring q -14
-KPX Aring quotedblright -54
-KPX Aring quoteright -56
-KPX Aring t -16
-KPX Aring u -16
-KPX Aring v -34
-KPX Aring w -24
-KPX Aring y -32
-KPX Ccedilla A -31
-KPX Odieresis A -35
-KPX Odieresis T -21
-KPX Odieresis V -29
-KPX Odieresis W -20
-KPX Odieresis X -32
-KPX Odieresis Y -50
-KPX Oacute A -35
-KPX Oacute T -21
-KPX Oacute V -29
-KPX Oacute W -20
-KPX Oacute Y -50
-KPX Ograve T -21
-KPX Ograve V -29
-KPX Ograve Y -50
-KPX Ocircumflex T -21
-KPX Ocircumflex V -29
-KPX Ocircumflex Y -50
-KPX Otilde T -21
-KPX Otilde V -29
-KPX Otilde Y -50
-KPX Udieresis A -32
-KPX Udieresis b -5
-KPX Udieresis comma -14
-KPX Udieresis m -5
-KPX Udieresis n -5
-KPX Udieresis p -5
-KPX Udieresis period -11
-KPX Udieresis r -5
-KPX Uacute A -32
-KPX Uacute comma -14
-KPX Uacute m -5
-KPX Uacute n -5
-KPX Uacute p -5
-KPX Uacute period -11
-KPX Uacute r -5
-KPX Ugrave A -32
-KPX Ucircumflex A -32
-KPX adieresis v -16
-KPX adieresis w -7
-KPX adieresis y -16
-KPX aacute v -17
-KPX aacute w -8
-KPX aacute y -17
-KPX agrave v -16
-KPX agrave w -7
-KPX agrave y -16
-KPX aring v -16
-KPX aring w -7
-KPX aring y -16
-KPX eacute v -17
-KPX eacute w -7
-KPX eacute y -18
-KPX ecircumflex v -16
-KPX ecircumflex w -6
-KPX ecircumflex y -17
-KPX odieresis t -7
-KPX odieresis v -19
-KPX odieresis w -9
-KPX odieresis x -22
-KPX odieresis y -21
-KPX oacute v -19
-KPX oacute w -9
-KPX oacute y -21
-KPX ograve v -19
-KPX ograve w -9
-KPX ograve y -21
-KPX ocircumflex t -7
-EndKernPairs
-EndKernData
-EndFontMetrics
diff --git a/src/fonts/nimbus-sans-l/n019064l.pfb b/src/fonts/nimbus-sans-l/n019064l.pfb
deleted file mode 100644
index ef8937f..0000000
--- a/src/fonts/nimbus-sans-l/n019064l.pfb
+++ /dev/null
Binary files differ
diff --git a/src/fonts/nimbus-sans-l/n019064l.pfm b/src/fonts/nimbus-sans-l/n019064l.pfm
deleted file mode 100644
index c6a1505..0000000
--- a/src/fonts/nimbus-sans-l/n019064l.pfm
+++ /dev/null
Binary files differ
diff --git a/src/fop-conf.xml b/src/fop-conf.xml
deleted file mode 100644
index 0a37fd6..0000000
--- a/src/fop-conf.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<fop version="1.0">
-
- <base>./</base>
-
- <font-base>./</font-base>
-
- <renderers>
- <renderer mime="application/pdf">
- <fonts>
- <directory>fonts/deja-vu-sans-mono</directory>
- <directory>fonts/nimbus-roman-no-9-l</directory>
- <directory>fonts/nimbus-sans-l</directory>
- </fonts>
- </renderer>
- </renderers>
-
-</fop>
diff --git a/src/guacamole-architecture.md b/src/guacamole-architecture.md
new file mode 100644
index 0000000..d175978
--- /dev/null
+++ b/src/guacamole-architecture.md
@@ -0,0 +1,142 @@
+Implementation and architecture
+===============================
+
+Guacamole is not a self-contained web application and is made up of many parts.
+The web application is actually intended to be simple and minimal, with the
+majority of the gruntwork performed by lower-level components.
+
+:::{image} images/guac-arch.png
+:width: 2.5in
+:::
+
+Users connect to a Guacamole server with their web browser. The Guacamole
+client, written in JavaScript, is served to users by a webserver within the
+Guacamole server. Once loaded, this client connects back to the server over
+HTTP using the Guacamole protocol.
+
+The web application deployed to the Guacamole server reads the Guacamole
+protocol and forwards it to guacd, the native Guacamole proxy. This proxy
+actually interprets the contents of the Guacamole protocol, connecting to any
+number of remote desktop servers on behalf of the user.
+
+The Guacamole protocol combined with guacd provide protocol agnosticism:
+neither the Guacamole client nor the web application need to be aware of what
+remote desktop protocol is actually being used.
+
+(guacamole-protocol-architecture)=
+
+The Guacamole protocol
+----------------------
+
+The web application does not understand any remote desktop protocol at all. It
+does not contain support for VNC or RDP or any other protocol supported by the
+Guacamole stack. It actually only understands the Guacamole protocol, which is
+a protocol for remote display rendering and event transport. While a protocol
+with those properties would naturally have the same abilities as a remote
+desktop protocol, the design principles behind a remote desktop protocol and
+the Guacamole protocol are different: the Guacamole protocol is not intended to
+implement the features of a specific desktop environment.
+
+As a remote display and interaction protocol, Guacamole implements a superset
+of existing remote desktop protocols. Adding support for a particular remote
+desktop protocol (like RDP) to Guacamole thus involves writing a middle layer
+which "translates" between the remote desktop protocol and the Guacamole
+protocol. Implementing such a translation is no different than implementing any
+native client, except that this particular implementation renders to a remote
+display rather than a local one.
+
+The middle layer that handles this translation is guacd.
+
+guacd
+-----
+
+guacd is the heart of Guacamole which dynamically loads support for remote
+desktop protocols (called "client plugins") and connects them to remote
+desktops based on instructions received from the web application.
+
+guacd is a daemon process which is installed along with Guacamole and runs in
+the background, listening for TCP connections from the web application. guacd
+also does not understand any specific remote desktop protocol, but rather
+implements just enough of the Guacamole protocol to determine which protocol
+support needs to be loaded and what arguments must be passed to it. Once a
+client plugin is loaded, it runs independently of guacd and has full control of
+the communication between itself and the web application until the client
+plugin terminates.
+
+guacd and all client plugins depend on a common library, libguac, which makes
+communication via the Guacamole protocol easier and a bit more abstract.
+
+(web-application)=
+
+The web application
+-------------------
+
+The part of Guacamole that a user actually interacts with is the web
+application.
+
+The web application, as mentioned before, does not implement any remote desktop
+protocol. It relies on guacd, and implements nothing more than a spiffy web
+interface and authentication layer.
+
+We chose to implement the server side of the web application in Java, but
+there's no reason that it can't be written in a different language. In fact,
+because Guacamole is intended be an API, we encourage this.
+
+RealMint
+--------
+
+Guacamole is now a generalized remote desktop gateway, but this was not always
+the case. Guacamole began as a purely text-based Telnet client written in
+JavaScript called RealMint ("RealMint" is an anagram for "terminal"). It was
+written mainly as a demonstration and, while intended to be useful, its main
+claim to fame was only that it was pure JavaScript.
+
+The tunnel used by RealMint was written in PHP. In contrast to Guacamole's HTTP
+tunnel, RealMint's tunnel used only simple long-polling and was inefficient.
+RealMint had a decent keyboard implementation which lives on now in parts of
+Guacamole's keyboard code, but this was really the extent of RealMint's
+features and usability.
+
+Given that it was just an implementation of a legacy protocol, and that several
+other JavaScript terminal emulators exist, most of which well-established and
+stable, the project was dropped.
+
+VNC Client
+----------
+
+Once the developers learned of the HTML5 canvas tag, and saw that it was
+already implemented in Firefox and Chrome, work started instead on a
+proof-of-concept JavaScript VNC client.
+
+This client was purely JavaScript with a Java server component, and worked by
+translating VNC into an XML-based version of the same. Its development was
+naturally driven by VNC's features, and its scope was limited to forwarding a
+single connection to a set of users. Although relatively slow, the
+proof-of-concept worked well enough that the project needed an online place to
+live, and was registered with SourceForge as "Guacamole" - an HTML5 VNC client.
+
+As Guacamole grew and became more than a proof-of-concept, the need for speed
+increased, and the old RealMint-style long polling was dropped, as was the use
+of XML.
+
+As WebSocket could not be trusted to be supported at the time, and Java had no
+WebSocket standard for servlets, an equivalent HTTP-based tunnel was developed.
+This tunnel is still used today if WebSocket cannot be used for any reason.
+
+(gateway)=
+
+Remote Desktop Gateway
+----------------------
+
+A faster text-based protocol was developed which could present the features of
+multiple remote desktop protocols, not just VNC. The entire system was
+rearchitected into a standard daemon, guacd, and a common library, libguac,
+which drove both the daemon and protocol support, which became extendable.
+
+The scope of the project expanded from an adequate VNC client to a performant
+HTML5 remote desktop gateway and general API. In its current state, Guacamole
+can be used as a central gateway to access any number of machines running
+different remote desktop servers. It provides extendable authentication, and in
+the case you need something more specialized, a general API for HTML5-based
+remote access.
+
diff --git a/src/guacamole-common-js.md b/src/guacamole-common-js.md
new file mode 100644
index 0000000..a1dc122
--- /dev/null
+++ b/src/guacamole-common-js.md
@@ -0,0 +1,379 @@
+guacamole-common-js
+===================
+
+The Guacamole project provides a JavaScript API for interfacing with other
+components that conform to the design of Guacamole, such as projects using
+libguac or guacamole-common. This API is called guacamole-common-js.
+
+guacamole-common-js provides a JavaScript implementation of a Guacamole client,
+as well as tunneling mechanisms for getting protocol data out of JavaScript and
+into guacd or the server side of a web application.
+
+For convenience, it also provides mouse and keyboard abstraction objects that
+translate JavaScript mouse, touch, and keyboard events into consistent data
+that Guacamole can more easily digest. The extendable on-screen keyboard that
+was developed for the Guacamole web application is also included.
+
+Guacamole client
+----------------
+
+The main benefit to using the JavaScript API is the full Guacamole client
+implementation, which implements all Guacamole instructions, and makes use of
+the tunnel implementations provided by both the JavaScript and Java APIs.
+
+Using the Guacamole client is straightforward. The client, like all other
+objects within the JavaScript API, is within the `Guacamole` namespace. It is
+instantiated given an existing, unconnected tunnel:
+
+```javascript
+var client = new Guacamole.Client(tunnel);
+```
+
+Once you have the client, it won't immediately appear within the DOM. You need
+to add its display element manually:
+
+```javascript
+document.body.appendChild(client.getDisplay().getElement());
+```
+
+At this point, the client will be visible, rendering all updates as soon as
+they are received through the tunnel.
+
+```javascript
+client.connect();
+```
+
+It is possible to pass arbitrary data to the tunnel during connection which can
+be used for authentication or for choosing a particular connection. When the
+`connect()` function of the Guacamole client is called, it in turn calls the
+`connect()` function of the tunnel originally given to the client, establishing
+a connection.
+
+:::{important}
+When creating the `Guacamole.Client`, the tunnel used must not already be
+connected. The `Guacamole.Client` will call the `connect()` function for you
+when its own `connect()` function is invoked. If the tunnel is already
+connected when it is given to the `Guacamole.Client`, connection may not work
+at all.
+:::
+
+In general, all instructions available within the Guacamole protocol are
+automatically handled by the Guacamole client, including instructions related
+to audio and video. The only instructions which you must handle yourself are
+"name" (used to name the connection), "clipboard" (used to update clipboard
+data on the client side), and "error" (used when something goes wrong
+server-side). Each of these instructions has a corresponding event handler; you
+need only supply functions to handle these events. If any of these event
+handlers are left unset, the corresponding instructions are simply ignored.
+
+HTTP tunnel
+-----------
+
+Both the Java and JavaScript API implement corresponding ends of an HTTP
+tunnel, based on `XMLHttpRequest`.
+
+The tunnel is a true stream - there is no polling. An initial request is made
+from the JavaScript side, and this request is handled on the Java side. While
+this request is open, data is streamed along the connection, and instructions
+within this stream are handled as soon as they are received by the client.
+
+While data is being streamed along this existing connection, a second
+connection attempt is made. Data continues to be streamed along the original
+connection until the server receives and handles the second request, at which
+point the original connection closes and the stream is transferred to the new
+connection.
+
+This process repeats, alternating between active streams, thus creating an
+unbroken sequence of instructions, while also allowing JavaScript to free any
+memory used by the previously active connection.
+
+The tunnel is created by supplying the relative URL to the server-side tunnel
+servlet:
+
+```javascript
+var tunnel = new Guacamole.Tunnel("tunnel");
+```
+
+Once created, the tunnel can be passed to a `Guacamole.Client` for use in a
+Guacamole connection.
+
+The tunnel actually takes care of the Guacamole protocol parsing on behalf of
+the client, triggering "oninstruction" events for every instruction received,
+splitting each element into elements of an array so that the client doesn't
+have to.
+
+Input abstraction
+-----------------
+
+Browsers can be rather finicky when it comes to keyboard and mouse input, not
+to mention touch events. There is little agreement on which keyboard events get
+fired when, and what detail about the event is made available to JavaScript.
+Touch and mouse events can also cause confusion, as most browsers will generate
+*both* events when the user touches the screen (for compatibility with
+JavaScript code that only handles mouse events), making it more difficult for
+applications to support both mouse and touch independently.
+
+The Guacamole JavaScript API abstracts mouse, keyboard, and touch interaction,
+providing several helper objects which act as an abstract interface between you
+and the browser events.
+
+(guacamole-mouse)=
+
+### Mouse
+
+Mouse event abstraction is provided by the `Guacamole.Mouse` object. Given an
+arbitrary DOM element, `Guacamole.Mouse` triggers onmousedown, onmousemove, and
+onmouseup events which are consistent across browsers. This object only
+responds to true mouse events. Mouse events which are actually the result of
+touch events are ignored.
+
+```javascript
+var element = document.getElementById("some-arbitrary-id");
+var mouse = new Guacamole.Mouse(element);
+
+mouse.onmousedown =
+mouse.onmousemove =
+mouse.onmouseup = function(state) {
+
+ // Do something with the mouse state received ...
+
+};
+```
+
+The handles of each event are given an instance of `Guacamole.Mouse.State`
+which represents the current state of the mouse, containing the state of each
+button (including the scroll wheel) as well as the X and Y coordinates of the
+pointer in pixels.
+
+(guacamole-touch)=
+
+### Touch
+
+Touch event abstraction is provided by either `Guacamole.Touchpad` (emulates a
+touchpad to generate artificial mouse events) or `Guacamole.Touchscreen`
+(emulates a touchscreen, again generating artificial mouse events). Guacamole
+uses the touchpad emulation, as this provides the most flexibility and
+mouse-like features, including scrollwheel and clicking with different buttons,
+but your preferences may differ.
+
+```javascript
+var element = document.getElementById("some-arbitrary-id");
+var touch = new Guacamole.Touchpad(element); // or Guacamole.Touchscreen
+
+touch.onmousedown =
+touch.onmousemove =
+touch.onmouseup = function(state) {
+
+ // Do something with the mouse state received ...
+
+};
+```
+
+Note that even though these objects are touch-specific, they still provide
+mouse events. The state object given to the event handlers of each event is
+still an instance of `Guacamole.Mouse.State`.
+
+Ultimately, you could assign the same event handler to all the events of both
+an instance of `Guacamole.Mouse` as well as `Guacamole.Touchscreen` or
+`Guacamole.Touchpad`, and you would magically gain mouse and touch support.
+This support, being driven by the needs of remote desktop, is naturally geared
+around the mouse and providing a reasonable means of interacting with it. For
+an actual mouse, events are translated simply and literally, while touch events
+go through additional emulation and heuristics. From the perspective of the
+user and the code, this is all transparent.
+
+(guacamole-keyboard)=
+
+### Keyboard
+
+Keyboard events in Guacamole are abstracted with the `Guacamole.Keyboard`
+object as only keyup and keydown events; there is no keypress like there is in
+JavaScript. Further, all the craziness of keycodes vs. scancodes vs. key
+identifiers normally present across browsers is abstracted away. All your event
+handlers will see is an X11 keysym, which represent every key unambiguously.
+Conveniently, X11 keysyms are also what the Guacamole protocol requires, so if
+you want to use `Guacamole.Keyboard` to drive key events sent over the
+Guacamole protocol, everything can be connected directly.
+
+Just like the other input abstraction objects, `Guacamole.Keyboard` requires a
+DOM element as an event target. Only key events directed at this element will
+be handled.
+
+```javascript
+var keyboard = new Guacamole.Keyboard(document);
+
+keyboard.onkeydown = function(keysym) {
+ // Do something ...
+};
+
+keyboard.onkeyup = function(keysym) {
+ // Do something ...
+};
+```
+
+In this case, we are using `document` as the event target, thus receiving all
+key events while the browser window (or tab) has focus.
+
+On-screen keyboard
+------------------
+
+The Guacamole JavaScript API also provides an extendable on-screen keyboard,
+`Guacamole.OnScreenKeyboard`, which requires the URL of an XML file describing
+the keyboard layout. The on-screen keyboard object provides no hard-coded
+layout information; the keyboard layout is described entirely within the XML
+layout file.
+
+### Keyboard layouts
+
+The keyboard layout XML included in the Guacamole web application would be a
+good place to start regarding how these layout files are written, but in
+general, the keyboard is simply a set of rows or columns, denoted with `<row>`
+and `<column>` tags respectively, where each can be nested within the other as
+desired.
+
+Each key is represented with a `<key>` tag, but this is not what the user sees,
+nor what generates the key event. Each key contains any number of `<cap>` tags,
+which represent the visible part of the key. The cap describes which X11
+keysym will be sent when the key is pressed. Each cap can be associated with
+any combination of arbitrary modifier flags which dictate when that cap is
+active.
+
+For example:
+
+```xml
+<keyboard lang="en_US" layout="example" size="5">
+ <row>
+ <key size="4">
+ <cap modifier="shift" keysym="0xFFE1">Shift</cap>
+ </key>
+ <key>
+ <cap>a</cap>
+ <cap if="shift">A</cap>
+ </key>
+ </row>
+</keyboard>
+```
+
+Here we have a very simple keyboard which defines only two keys: "shift" (a
+modifier) and the letter "a". When "shift" is pressed, it sets the "shift"
+modifier, affecting other keys in the keyboard. The "a" key has two caps: one
+lowercase (the default) and one uppercase (which requires the shift modifier to
+be active).
+
+Notice that the shift key needed the keysym explicitly specified, while the "a"
+key did not. This is because the on-screen keyboard will automatically derive
+the correct keysym from the text of the key cap if the text contains only a
+single character.
+
+(displaying-osk)=
+
+### Displaying the keyboard
+
+Once you have a keyboard layout available, adding an on-screen keyboard to your
+application is simple:
+
+```javascript
+// Add keyboard to body
+var keyboard = new Guacamole.OnScreenKeyboard("path/to/layout.xml");
+document.body.appendChild(keyboard.getElement());
+
+// Set size of keyboard to 100 pixels
+keyboard.resize(100);
+```
+
+Here, we have explicitly specified the width of the keyboard as 100 pixels.
+Normally, you would determine this by inspecting the width of the containing
+component, or by deciding on a reasonable width beforehand. Once the width is
+given, the height of the keyboard is determined based on the arrangement of
+each row.
+
+### Styling the keyboard
+
+While the `Guacamole.OnScreenKeyboard` object will handle most of the layout,
+you will still need to style everything yourself with CSS to get the elements
+to render properly and the keys to change state when clicked or activated. It
+defines several CSS classes, which you will need to manually style to get
+things looking as desired:
+
+`guac-keyboard`
+: This class is assigned to the root element containing the entire keyboard,
+ returned by `getElement()`,
+
+`guac-keyboard-row`
+: Assigned to the `div` elements which contain each row.
+
+`guac-keyboard-column`
+: Assigned to the `div` elements which contain each column.
+
+`guac-keyboard-gap`
+: Assigned to any `div` elements created as a result of `<gap>` tags in the
+ keyboard layout. `<gap>` tags are intended to behave as keys with no visible
+ styling or caps.
+
+`guac-keyboard-key-container`
+: Assigned to the `div` element which contains a key, and provides that key
+ with its required dimensions. It is this element that will be scaled relative
+ to the size specified in the layout XML and the size given to the `resize()`
+ function.
+
+`guac-keyboard-key`
+: Assigned to the `div` element which represents the actual key, not the cap.
+ This element will not directly contain text, but it will contain all caps
+ that this key can have. With clever CSS rules, you can take advantage of this
+ and cause inactive caps to appear on the key in a corner (for example), or
+ hide them entirely.
+
+`guac-keyboard-cap`
+: Assigned to the `div` element representing a key cap. Each cap is a child of
+ its corresponding key, and it is up to the author of the CSS rules to hide or
+ show or reposition each cap appropriately. Each cap will contain the display
+ text defined within the `<cap>` element in the layout XML.
+
+{samp}`guac-keyboard-requires-{MODIFIER}`
+: Added to the cap element when that cap requires a specific modifier.
+
+{samp}`guac-keyboard-uses-{MODIFIER}`
+: Added to the key element when any cap contained within it requires a specific
+ modifier.
+
+{samp}`guac-keyboard-modifier-{MODIFIER}`
+: Added to and removed from the root keyboard element when a modifier key is
+ activated or deactivated respectively.
+
+`guac-keyboard-pressed`
+: Added to and removed from any key element as it is pressed and released
+ respectively.
+
+:::{important}
+The CSS rules required for the on-screen keyboard to work as expected can be
+quite complex. Looking over the CSS rules used by the on-screen keyboard in the
+Guacamole web application would be a good place to start to see how the
+appearance of each key can be driven through the simple class changes described
+above.
+
+Inspecting the elements of an active on-screen keyboard within the Guacamole
+web application with the developer tools of your favorite browser is also a
+good idea.
+:::
+
+(osk-event-handling)=
+
+### Handling key events
+
+Key events generated by the on-screen keyboard are identical to those of
+`Guacamole.Keyboard` in that they consist only of a single X11 keysym. Only
+keyup and keydown events exist, as before; there is no keypress event.
+
+```javascript
+// Assuming we have an instance of Guacamole.OnScreenKeyboard already
+// called "keyboard"
+
+keyboard.onkeydown = function(keysym) {
+ // Do something ...
+};
+
+keyboard.onkeyup = function(keysym) {
+ // Do something ...
+};
+```
+
diff --git a/src/guacamole-common.md b/src/guacamole-common.md
new file mode 100644
index 0000000..bd5d609
--- /dev/null
+++ b/src/guacamole-common.md
@@ -0,0 +1,137 @@
+guacamole-common
+================
+
+The Java API provided by the Guacamole project is called guacamole-common. It
+provides a basic means of tunneling data between the JavaScript client provided
+by guacamole-common-js and the native proxy daemon, guacd, and for dealing with
+the Guacamole protocol. The purpose of this library is to facilitate the
+creation of custom tunnels between the JavaScript client and guacd, allowing
+your Guacamole-driven web application to enforce its own security model, if
+any, and dictate exactly what connections are established.
+
+(java-http-tunnel)=
+
+HTTP tunnel
+-----------
+
+The Guacamole Java API implements the HTTP tunnel using a servlet called
+`GuacamoleHTTPTunnelServlet`. This servlet handles all requests coming to it
+over HTTP from the JavaScript client, and translates them into connect, read,
+or write requests, which each get dispatched to the `doConnect()`, `doRead()`,
+and `doWrite()` functions accordingly.
+
+Normally, you wouldn't touch the `doRead()` and `doWrite()` functions, as these
+have already been written to properly handle the requests of the JavaScript
+tunnel, and if you feel the need to touch these functions, you are probably
+better off writing your own tunnel implementation, although such a thing is
+difficult to do in a performant way.
+
+When developing an application based on the Guacamole API, you should use
+`GuacamoleHTTPTunnelServlet` by extending it, implementing your own version of
+`doConnect()`, which is the only abstract function it defines. The tutorial
+later in this book demonstrating how to write a Guacamole-based web application
+shows the basics of doing this, but generally, `doConnect()` is an excellent
+place for authentication or other validation, as it is the responsibility of
+`doConnect()` to create (or not create) the actual tunnel. If `doConnect()`
+does not create the tunnel, communication between the JavaScript client and
+guacd cannot take place, which is an ideal power to have as an authenticator.
+
+The `doConnect()` function is expected to return a new `GuacamoleTunnel`, but
+it is completely up to the implementation to decide how that tunnel is to be
+created. The already-implemented parts of `GuacamoleHTTPTunnelServlet` then
+return the unique identifier of this tunnel to the JavaScript client, allowing
+its own tunnel implementation to continue to communicate with the tunnel
+existing on the Java side.
+
+Instances of `GuacamoleTunnel` are associated with a `GuacamoleSocket`, which
+is the abstract interface surrounding the low-level connection to guacd.
+Overall, there is a socket (`GuacamoleSocket`) which provides a TCP connection
+to guacd. This socket is exposed to `GuacamoleTunnel`, which provides abstract
+protocol access around what is actually (but secretly, through the abstraction
+of the API) a TCP socket.
+
+The Guacamole web application extends this tunnel servlet in order to implement
+authentication at the lowest possible level, effectively prohibiting
+communication between the client and any remote desktops unless they have
+properly authenticated. Your own implementation can be considerably simpler,
+especially if you don't need authentication:
+
+```java
+public class MyGuacamoleTunnelServlet
+ extends GuacamoleHTTPTunnelServlet {
+
+ @Override
+ protected GuacamoleTunnel doConnect(HttpServletRequest request)
+ throws GuacamoleException {
+
+ // Connect to guacd here (this is a STUB)
+ GuacamoleSocket socket;
+
+ // Return a new tunnel which uses the connected socket
+ return new SimpleGuacamoleTunnel(socket);
+
+ }
+
+}
+```
+
+(java-protocol-usage)=
+
+Using the Guacamole protocol
+----------------------------
+
+guacamole-common provides basic low-level support for the Guacamole protocol.
+This low-level support is leveraged by the HTTP tunnel implementation to
+satisfy the requirements of the JavaScript client implementation, as the
+JavaScript client expects the handshake procedure to have already taken place.
+This support exists through the `GuacamoleReader` and `GuacamoleWriter`
+classes, which are similar to Java's `Reader` and `Writer` classes, except that
+they deal with the Guacamole protocol specifically, and thus have slightly
+different contracts.
+
+(java-reading-protocol)=
+
+### `GuacamoleReader`
+
+`GuacamoleReader` provides a very basic `read()` function which is required to
+return one or more complete instructions in a `char` array. It also provides
+the typical `available()` function, which informs you whether `read()` is
+likely to block the next time it is called, and an even more abstract version
+of `read()` called `readInstruction()` which returns one instruction at a time,
+wrapped within a `GuacamoleInstruction` instance.
+
+Normally, you would not need to use this class yourself. It is used by
+`ConfiguredGuacamoleSocket` to complete the Guacamole protocol handshake
+procedure, and it is used by `GuacamoleHTTPTunnelServlet` within `doRead()` to
+implement the reading half of the tunnel.
+
+The only concrete implementation of `GuacamoleReader` is
+`ReaderGuacamoleReader`, which wraps a Java `Reader`, using that as the source
+for data to parse into Guacamole instructions. Again, you would not normally
+directly use this class, nor instantiate it yourself. A working, concrete
+instance of `GuacamoleReader` can be retrieved from any `GuacamoleSocket` or
+`GuacamoleTunnel`.
+
+(java-writing-protocol)=
+
+### `GuacamoleWriter`
+
+`GuacamoleWriter` provides a very basic `write()` function and a more abstract
+version called `writeInstruction()` which writes instances of
+`GuacamoleInstruction`. These functions are analogous to the `read()` and
+`readInstruction()` functions provided by `GuacamoleReader`, and have similar
+restrictions: the contract imposed by `write()` requires that written
+instructions be complete.
+
+The only concrete implementation of `GuacamoleWriter` is
+`WriterGuacamoleWriter`, which wraps a Java `Writer`, using that as the
+destination for Guacamole instruction data, but you would not normally directly
+use this class, nor instantiate it yourself. It is used by
+`ConfiguredGuacamoleSocket` to complete the Guacamole protocol handshake
+procedure, and it is used by `GuacamoleHTTPTunnelServlet` within `doWrite()` to
+implement the writing half of the tunnel.
+
+If necessary, a `GuacamoleWriter` can be retrieved from any `GuacamoleSocket`
+or `GuacamoleTunnel`, but in most cases, the classes provided by the Guacamole
+Java API which already use `GuacamoleWriter` will be sufficient.
+
diff --git a/src/guacamole-docker.md b/src/guacamole-docker.md
new file mode 100644
index 0000000..7ca4be4
--- /dev/null
+++ b/src/guacamole-docker.md
@@ -0,0 +1,707 @@
+Installing Guacamole with Docker
+================================
+
+Guacamole can be deployed using Docker, removing the need to build
+guacamole-server from source or configure the web application manually. The
+Guacamole project provides officially-supported Docker images for both
+Guacamole and guacd which are kept up-to-date with each release.
+
+A typical Docker deployment of Guacamole will involve three separate
+containers, linked together at creation time:
+
+`guacamole/guacd`
+: Provides the guacd daemon, built from the released guacamole-server source
+ with support for VNC, RDP, SSH, telnet, and Kubernetes.
+
+`guacamole/guacamole`
+: Provides the Guacamole web application running within Tomcat 8 with support
+ for WebSocket. The configuration necessary to connect to guacd, MySQL,
+ PostgreSQL, LDAP, etc. will be generated automatically when the image starts
+ based on Docker links or environment variables.
+
+`mysql` or `postgresql`
+: Provides the database that Guacamole will use for authentication and storage
+ of connection configuration data.
+
+This separation is important, as it facilitates upgrades and maintains proper
+separation of concerns. With the database separate from Guacamole and guacd,
+those containers can be freely destroyed and recreated at will. The only
+container which must persist data through upgrades is the database.
+
+(guacd-docker-image)=
+
+Running the guacd Docker image
+------------------------------
+
+The guacd Docker image is built from the released guacamole-server source with
+support for VNC, RDP, SSH, telnet, and Kubernetes. Common pitfalls like
+installing the required dependencies, installing fonts for SSH, telnet, or
+Kubernetes, and ensuring the FreeRDP plugins are installed to the correct
+location are all taken care of. It will simply just work.
+
+(guacd-docker-guacamole)=
+
+### Running guacd for use by the Guacamole Docker image
+
+When running the guacd image with the intent of linking to a Guacamole
+container, no ports need be exposed on the network. Access to these ports will
+be handled automatically by Docker during linking, and the Guacamole image will
+properly detect and configure the connection to guacd.
+
+```console
+$ docker run --name some-guacd -d guacamole/guacd
+```
+When run in this manner, guacd will be listening on its default port 4822, but
+this port will only be available to Docker containers that have been explicitly
+linked to `some-guacd`.
+
+The log level of guacd can be controlled with the `GUACD_LOG_LEVEL` environment
+variable. The default value is `info`, and can be set to any of the valid
+settings for the guacd log flag (-L).
+
+```console
+$ docker run -e GUACD_LOG_LEVEL=debug -d guacamole/guacd
+```
+
+(guacd-docker-external)=
+
+### Running guacd for use by services outside Docker
+
+If you are not going to use the Guacamole image, you can still leverage the
+guacd image for ease of installation and maintenance. By exposing the guacd
+port, 4822, services external to Docker will be able to access guacd.
+
+:::{important}
+*Take great care when doing this* - guacd is a passive proxy and does not
+perform any kind of authentication.
+
+If you do not properly isolate guacd from untrusted parts of your network,
+malicious users may be able to use guacd as a jumping point to other systems.
+:::
+
+```console
+$ docker run --name some-guacd -d -p 4822:4822 guacamole/guacd
+```
+
+guacd will now be listening on port 4822, and Docker will expose this port on
+the same server hosting Docker. Other services, such as an instance of Tomcat
+running outside of Docker, will be able to connect to guacd directly.
+
+(guacamole-docker-image)=
+
+The Guacamole Docker image
+--------------------------
+
+The Guacamole Docker image is built on top of a standard Tomcat 8 image and
+takes care of all configuration automatically. The configuration information
+required for guacd and the various authentication mechanisms are specified with
+environment variables or Docker links given when the container is created.
+
+:::{important}
+If using [PostgreSQL](guacamole-docker-postgresql) or [MySQL](guacamole-docker-mysql)
+for authentication, *you will need to initialize the database manually*.
+Guacamole will not automatically create its own tables, but SQL scripts are
+provided to do this.
+:::
+
+Once the Guacamole image is running, Guacamole will be accessible at
+{samp}`http://{HOSTNAME}:8080/guacamole/`, where `HOSTNAME` is the hostname or
+address of the machine hosting Docker.
+
+(guacamole-docker-config-via-env)=
+
+### Configuring Guacamole when using Docker
+
+When running Guacamole using Docker, the traditional approach to configuring
+Guacamole by editing `guacamole.properties` is less convenient. When using
+Docker, you may wish to make use of the `enable-environment-properties`
+configuration property, which allows you to specify values for arbitrary
+Guacamole configuration properties using environment variables. This is covered
+in [](configuring-guacamole).
+
+(guacamole-docker-guacd)=
+
+### Connecting Guacamole to guacd
+
+The Guacamole Docker image needs to be able to connect to guacd to establish
+remote desktop connections, just like any other Guacamole deployment. The
+connection information needed by Guacamole will be provided either via a Docker
+link or through environment variables.
+
+If you will be using Docker to provide guacd, and you wish to use a Docker link
+to connect the Guacamole image to guacd, the connection details are implied by
+the Docker link:
+
+```console
+$ docker run --name some-guacamole \
+ --link some-guacd:guacd \
+ ...
+ -d -p 8080:8080 guacamole/guacamole
+```
+
+If you are not using Docker to provide guacd, you will need to provide the
+network connection information yourself using additional environment variables:
+
+`GUACD_HOSTNAME`
+: The hostname of the guacd instance to use to establish remote desktop
+ connections. *This is required if you are not using Docker to provide guacd.*
+
+`GUACD_POST`
+: The port that Guacamole should use when connecting to guacd. This environment
+ variable is optional. If not provided, the standard guacd port of 4822 will
+ be used.
+
+The `GUACD_HOSTNAME` and, if necessary, `GUACD_PORT` environment variables can
+thus be used in place of a Docker link if using a Docker link is impossible or
+undesirable:
+
+```console
+$ docker run --name some-guacamole \
+ -e GUACD_HOSTNAME=172.17.42.1 \
+ -e GUACD_PORT=4822 \
+ ...
+ -d -p 8080:8080 guacamole/guacamole
+```
+
+*A connection to guacd is not the only thing required for Guacamole to work*;
+some authentication mechanism needs to be configured, as well.
+[MySQL](guacamole-docker-mysql), [PostgreSQL](guacamole-docker-postgresql), and
+[LDAP](guacamole-docker-ldap) are supported for this, and are described in more
+detail in the sections below. If the required configuration options for at
+least one authentication mechanism are not provided, the Guacamole image will
+not be able to start up, and you will see an error.
+
+(guacamole-docker-mysql)=
+
+### MySQL authentication
+
+To use Guacamole with the MySQL authentication backend, you will need either a
+Docker container running the `mysql` image, or network access to a working
+installation of MySQL. The connection to MySQL can be specified using either
+environment variables or a Docker link.
+
+(initializing-guacamole-docker-mysql)=
+
+#### Initializing the MySQL database
+
+If your database is not already initialized with the Guacamole schema, you will
+need to do so prior to using Guacamole. A convenience script for generating the
+necessary SQL to do this is included in the Guacamole image.
+
+To generate a SQL script which can be used to initialize a fresh MySQL database
+as documented in [](jdbc-auth):
+
+```console
+$ docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql
+```
+
+Alternatively, you can use the SQL scripts included with the database
+authentication.
+
+Once this script is generated, you must:
+
+1. Create a database for Guacamole within MySQL, such as `guacamole_db`.
+
+2. Create a user for Guacamole within MySQL with access to this database, such
+ as `guacamole_user`.
+
+3. Run the script on the newly-created database.
+
+The process for doing this via the {command}`mysql` utility included with MySQL
+is documented [](jdbc-auth).
+
+(guacamole-docker-mysql-connecting)=
+
+#### Connecting Guacamole to MySQL
+
+If your MySQL database is provided by another Docker container, and you wish to
+use a Docker link to connect the Guacamole image to your database, the
+connection details are implied by the Docker link itself:
+
+```console
+$ docker run --name some-guacamole \
+ --link some-guacd:guacd \
+ --link some-mysql:mysql \
+ ...
+ -d -p 8080:8080 guacamole/guacamole
+```
+
+If you are not using Docker to provide your MySQL database, you will need to
+provide the network connection information yourself using additional
+environment variables:
+
+`MYSQL_HOSTNAME`
+: The hostname of the database to use for Guacamole authentication. *This is
+ required if you are not using Docker to provide your MySQL database.*
+
+`MYSQL_PORT`
+: The port that Guacamole should use when connecting to MySQL. This environment
+ variable is optional. If not provided, the standard MySQL port of 3306 will
+ be used.
+
+The `MYSQL_HOSTNAME` and, if necessary, `MYSQL_PORT` environment variables can
+thus be used in place of a Docker link if using a Docker link is impossible or
+undesirable:
+
+```console
+$ docker run --name some-guacamole \
+ --link some-guacd:guacd \
+ -e MYSQL_HOSTNAME=172.17.42.1 \
+ ...
+ -d -p 8080:8080 guacamole/guacamole
+```
+
+Note that a Docker link to guacd (the `--link some-guacd:guacd` option above)
+is not required any more than a Docker link is required for MySQL. The
+connection information for guacd can be specified using environment variables,
+as described in [](guacamole-docker-guacd).
+
+(guacamole-docker-mysql-required-vars)=
+
+#### Required environment variables
+
+Using MySQL for authentication requires additional configuration parameters
+specified via environment variables. These variables collectively describe how
+Guacamole will connect to MySQL:
+
+`MYSQL_DATABASE`
+: The name of the database to use for Guacamole authentication.
+
+`MYSQL_USER`
+: The user that Guacamole will use to connect to MySQL.
+
+`MYSQL_PASSWORD`
+: The password that Guacamole will provide when connecting to MySQL as
+ `MYSQL_USER`.
+
+If any required environment variables are omitted, you will receive an error
+message in the logs, and the image will stop. You will then need to recreate
+the container with the proper variables specified.
+
+(guacamole-docker-mysql-optional-vars)=
+
+#### Optional environment variables
+
+Additional optional environment variables may be used to override Guacamole's
+default behavior with respect to concurrent connection use by one or more
+users. Concurrent use of connections and connection groups can be limited to an
+overall maximum and/or a per-user maximum:
+
+
+`MYSQL_ABSOLUTE_MAX_CONNECTIONS`
+: The absolute maximum number of concurrent connections to allow at any time,
+ regardless of the Guacamole connection or user involved. If set to "0", this
+ will be unlimited. Because this limit applies across all Guacamole
+ connections, it cannot be overridden if set.
+
+ *By default, the absolute total number of concurrent connections is unlimited
+ ("0").*
+
+`MYSQL_DEFAULT_MAX_CONNECTIONS`
+: The maximum number of concurrent connections to allow to any one Guacamole
+ connection. If set to "0", this will be unlimited. This can be overridden on
+ a per-connection basis when editing a connection.
+
+ *By default, overall concurrent use of connections is unlimited ("0").*
+
+`MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS`
+: The maximum number of concurrent connections to allow to any one Guacamole
+ connection group. If set to "0", this will be unlimited. This can be
+ overridden on a per-group basis when editing a connection group.
+
+ *By default, overall concurrent use of connection groups is unlimited ("0").*
+
+`MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER`
+: The maximum number of concurrent connections to allow a single user to
+ maintain to any one Guacamole connection. If set to "0", this will be
+ unlimited. This can be overridden on a per-connection basis when editing a
+ connection.
+
+ *By default, per-user concurrent use of connections is unlimited ("0").*
+
+`MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER`
+: The maximum number of concurrent connections to allow a single user to
+ maintain to any one Guacamole connection group. If set to "0", this will be
+ unlimited. This can be overridden on a per-group basis when editing a
+ connection group.
+
+ *By default, per-user concurrent use of connection groups is limited to one
+ ("1")*, to prevent a balancing connection group from being completely
+ exhausted by one user alone.
+
+`MYSQL_AUTO_CREATE_ACCOUNTS`
+: Whether or not accounts that do not exist in the MySQL database will be
+ automatically created when successfully authenticated through other modules.
+ If set to "true" accounts will be automatically created. Otherwise, and by
+ default, accounts will not be automatically created and will need to be
+ manually created in order for permissions within the MySQL database extension
+ to be assigned to users authenticated with other modules.
+
+(guacamole-docker-postgresql)=
+
+### PostgreSQL authentication
+
+To use Guacamole with the PostgreSQL authentication backend, you will
+need either a Docker container running the `postgres` image, or
+network access to a working installation of PostgreSQL. The connection
+to PostgreSQL can be specified using either environment variables or a
+Docker link.
+
+(initializing-guacamole-docker-postgresql)=
+
+#### Initializing the PostgreSQL database
+
+If your database is not already initialized with the Guacamole schema, you will
+need to do so prior to using Guacamole. A convenience script for generating the
+necessary SQL to do this is included in the Guacamole image.
+
+To generate a SQL script which can be used to initialize a fresh PostgreSQL
+database as documented in [](jdbc-auth):
+
+```console
+$ docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --postgres > initdb.sql
+```
+
+Alternatively, you can use the SQL scripts included with the database
+authentication.
+
+Once this script is generated, you must:
+
+1. Create a database for Guacamole within PostgreSQL, such as
+ `guacamole_db`.
+
+2. Run the script on the newly-created database.
+
+3. Create a user for Guacamole within PostgreSQL with access to the tables and
+ sequences of this database, such as `guacamole_user`.
+
+The process for doing this via the {command}`psql` and {command}`createdb`
+utilities included with PostgreSQL is documented in [](jdbc-auth).
+
+(guacamole-docker-postgresql-connecting)=
+
+#### Connecting Guacamole to PostgreSQL
+
+If your PostgreSQL database is provided by another Docker container, and you
+wish to use a Docker link to connect the Guacamole image to your database, the
+connection details are implied by the Docker link itself:
+
+```console
+$ docker run --name some-guacamole \
+ --link some-guacd:guacd \
+ --link some-postgres:postgres \
+ ...
+ -d -p 8080:8080 guacamole/guacamole
+```
+
+If you are not using Docker to provide your PostgreSQL database, you will need
+to provide the network connection information yourself using additional
+environment variables:
+
+`POSTGRES_HOSTNAME`
+: The hostname of the database to use for Guacamole authentication. *This is
+ required if you are not using Docker to provide your PostgreSQL database.*
+
+`POSTGRES_PORT`
+: The port that Guacamole should use when connecting to PostgreSQL. This
+ environment variable is optional. If not provided, the standard PostgreSQL
+ port of 5432 will be used.
+
+The `POSTGRES_HOSTNAME` and, if necessary, `POSTGRES_PORT` environment
+variables can thus be used in place of a Docker link if using a Docker link is
+impossible or undesirable:
+
+```console
+$ docker run --name some-guacamole \
+ --link some-guacd:guacd \
+ -e POSTGRES_HOSTNAME=172.17.42.1 \
+ ...
+ -d -p 8080:8080 guacamole/guacamole
+```
+
+Note that a Docker link to guacd (the `--link some-guacd:guacd` option above)
+is not required any more than a Docker link is required for PostgreSQL. The
+connection information for guacd can be specified using environment variables,
+as described in [](guacamole-docker-guacd).
+
+(guacamole-docker-postgresql-required-vars)=
+
+#### Required environment variables
+
+Using PostgreSQL for authentication requires additional configuration
+parameters specified via environment variables. These variables collectively
+describe how Guacamole will connect to PostgreSQL:
+
+`POSTGRES_DATABASE`
+: The name of the database to use for Guacamole authentication.
+
+`POSTGRES_USER`
+: The user that Guacamole will use to connect to PostgreSQL.
+
+`POSTGRES_PASSWORD`
+: The password that Guacamole will provide when connecting to PostgreSQL as
+ `POSTGRES_USER`.
+
+If any required environment variables are omitted, you will receive an
+error message in the logs, and the image will stop. You will then need
+to recreate the container with the proper variables specified.
+
+(guacamole-docker-postgresql-optional-vars)=
+
+#### Optional environment variables
+
+Additional optional environment variables may be used to override Guacamole's
+default behavior with respect to concurrent connection use by one or more
+users. Concurrent use of connections and connection groups can be limited to an
+overall maximum and/or a per-user maximum:
+
+`POSTGRES_ABSOLUTE_MAX_CONNECTIONS`
+: The absolute maximum number of concurrent connections to allow at any time,
+ regardless of the Guacamole connection or user involved. If set to "0", this
+ will be unlimited. Because this limit applies across all Guacamole
+ connections, it cannot be overridden if set.
+
+ *By default, the absolute total number of concurrent connections is unlimited
+ ("0").*
+
+`POSTGRES_DEFAULT_MAX_CONNECTIONS`
+: The maximum number of concurrent connections to allow to any one Guacamole
+ connection. If set to "0", this will be unlimited. This can be overridden on
+ a per-connection basis when editing a connection.
+
+ *By default, overall concurrent use of connections is unlimited ("0").*
+
+`POSTGRES_DEFAULT_MAX_GROUP_CONNECTIONS`
+: The maximum number of concurrent connections to allow to any one Guacamole
+ connection group. If set to "0", this will be unlimited. This can be
+ overridden on a per-group basis when editing a connection group.
+
+ *By default, overall concurrent use of connection groups is unlimited ("0").*
+
+`POSTGRES_DEFAULT_MAX_CONNECTIONS_PER_USER`
+: The maximum number of concurrent connections to allow a single user to
+ maintain to any one Guacamole connection. If set to "0", this will be
+ unlimited. This can be overridden on a per-connection basis when editing a
+ connection.
+
+ *By default, per-user concurrent use of connections is unlimited ("0").*
+
+`POSTGRES_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER`
+: The maximum number of concurrent connections to allow a single user to
+ maintain to any one Guacamole connection group. If set to "0", this will be
+ unlimited. This can be overridden on a per-group basis when editing a
+ connection group.
+
+ *By default, per-user concurrent use of connection groups is limited to one
+ ("1")*, to prevent a balancing connection group from being completely
+ exhausted by one user alone.
+
+`POSTGRES_AUTO_CREATE_ACCOUNTS`
+: Whether or not accounts that do not exist in the PostgreSQL database will be
+ automatically created when successfully authenticated through other modules.
+ If set to "true", accounts will be automatically created. Otherwise, and by
+ default, accounts will not be automatically created and will need to be
+ manually created in order for permissions within the PostgreSQL database
+ extension to be assigned to users authenticated with other modules.
+
+Optional environment variables may also be used to override Guacamole's default
+behavior with respect to timeouts at the database and network level:
+
+`POSTGRES_DEFAULT_STATEMENT_TIMEOUT`
+: The number of seconds the driver will wait for a response from the database,
+ before aborting the query. A value of 0 (the default) means the timeout is
+ disabled.
+
+`POSTGRES_SOCKET_TIMEOUT`
+: The number of seconds to wait for socket read operations. If reading from the
+ server takes longer than this value, the connection will be closed. This can
+ be used to handle network problems such as a dropped connection to the
+ database. Similar to `POSTGRES_DEFAULT_STATEMENT_TIMEOUT`, it will also abort
+ queries that take too long. A value of 0 (the default) means the timeout is
+ disabled.
+
+(guacamole-docker-ldap)=
+
+### LDAP authentication
+
+To use Guacamole with the LDAP authentication backend, you will need network
+access to an LDAP directory. Unlike MySQL and PostgreSQL, the Guacamole Docker
+image does not support Docker links for LDAP; the connection information *must*
+be specified using environment variables:
+
+
+`LDAP_HOSTNAME`
+: The hostname or IP address of your LDAP server.
+
+`LDAP_PORT`
+: The port your LDAP server listens on. By default, this will be 389 for
+ unencrypted LDAP or LDAP using STARTTLS, and 636 for LDAP over SSL (LDAPS).
+
+`LDAP_ENCRYPTION_METHOD`
+: The encryption mechanism that Guacamole should use when communicating with
+ your LDAP server. Legal values are "none" for unencrypted LDAP, "ssl" for
+ LDAP over SSL/TLS (commonly known as LDAPS), or "starttls" for STARTTLS. If
+ omitted, encryption will not be used.
+
+Only the `LDAP_HOSTNAME` variable is required, but you may also need to specify
+`LDAP_PORT` or `LDAP_ENCRYPTION_METHOD` if your LDAP directory uses encryption
+or listens on a non-standard port:
+
+```console
+$ docker run --name some-guacamole \
+ --link some-guacd:guacd \
+ -e LDAP_HOSTNAME=172.17.42.1 \
+ ...
+ -d -p 8080:8080 guacamole/guacamole
+```
+
+Note that a Docker link to guacd (the `--link some-guacd:guacd` option above)
+is not required. Similar to LDAP, the connection information for guacd can be
+specified using environment variables, as described in [](guacamole-docker-guacd).
+
+(guacamole-docker-ldap-required-vars)=
+
+#### Required environment variables
+
+Using LDAP for authentication requires additional configuration parameters
+specified via environment variables. These variables collectively describe how
+Guacamole will query your LDAP directory:
+
+`LDAP_USER_BASE_DN`
+: The base of the DN for all Guacamole users. All Guacamole users that will be
+ authenticating against LDAP must be descendents of this base DN.
+
+As with the other authentication mechanisms, if any required environment
+variables are omitted (including those required for connecting to the LDAP
+directory over the network), you will receive an error message in the logs, and
+the image will stop. You will then need to recreate the container with the
+proper variables specified.
+
+(guacamole-docker-ldap-optional-vars)=
+
+#### Optional environment variables
+
+Additional optional environment variables may be used to configure the details
+of your LDAP directory hierarchy, or to enable more flexible searching for user
+accounts:
+
+`LDAP_GROUP_BASE_DN`
+: The base of the DN for all groups that may be referenced within Guacamole
+ configurations using the standard seeAlso attribute. All groups which will be
+ used to control access to Guacamole configurations must be descendents of
+ this base DN. *If this variable is omitted, the seeAlso attribute will have
+ no effect on Guacamole configurations.*
+
+`LDAP_SEARCH_BIND_DN`
+: The DN (Distinguished Name) of the user to bind as when authenticating users
+ that are attempting to log in. If specified, Guacamole will query the LDAP
+ directory to determine the DN of each user that logs in. If omitted, each
+ user's DN will be derived directly using the base DN specified with
+ `LDAP_USER_BASE_DN`.
+
+`LDAP_SEARCH_BIND_PASSWORD`
+: The password to provide to the LDAP server when binding as
+ `LDAP_SEARCH_BIND_DN` to authenticate other users. This variable is only
+ used if `LDAP_SEARCH_BIND_DN` is specified. If omitted, but
+ `LDAP_SEARCH_BIND_DN` is specified, Guacamole will attempt to bind with the
+ LDAP server without a password.
+
+`LDAP_USERNAME_ATTRIBUTE`
+: The attribute or attributes which contain the username within all Guacamole
+ user objects in the LDAP directory. Usually, and by default, this will simply
+ be "uid". If your LDAP directory contains users whose usernames are dictated
+ by different attributes, multiple attributes can be specified here, separated
+ by commas, but beware: *doing so requires that a search DN be provided with
+ `LDAP_SEARCH_BIND_DN`*.
+
+`LDAP_CONFIG_BASE_DN`
+: The base of the DN for all Guacamole configurations. If omitted, the
+ configurations of Guacamole connections will simply not be queried from the
+ LDAP directory, and you will need to store them elsewhere, such as within a
+ MySQL or PostgreSQL database.
+
+As documented in [](ldap-auth), Guacamole does support combining LDAP with a
+MySQL or PostgreSQL database, and this can be configured with the Guacamole
+Docker image, as well. Each of these authentication mechanisms is independently
+configurable using their respective environment variables, and by providing the
+required environment variables for multiple systems, Guacamole will
+automatically be configured to use each when the Docker image starts.
+
+(guacamole-docker-header-auth)=
+
+### Header Authentication
+
+The header authentication extension can be used to authenticate Guacamole
+through a trusted third-party server, where the authenticated user's username
+is passed back to Guacamole via a specific HTTP header. The following are
+valid Docker variables for enabling and configuring header authentication:
+
+`HEADER_ENABLED`
+: Enables authentication via the header extension, which causes the extension
+ to be loaded when Guacamole starts. By default this is false and the header
+ extension will not be loaded.
+
+`HTTP_AUTH_HEADER`
+: Optional environment variable that, if set, configures the name of the HTTP
+ header that will be used used to authenticate the user to Guacamole. If this
+ is not specified the default value of REMOTE_USER will be used.
+
+(guacamole-docker-guacamole-home)=
+
+### Custom extensions and `GUACAMOLE_HOME`
+
+If you have your own or third-party extensions for Guacamole which are not
+supported by the Guacamole Docker image, but are compatible with the version of
+Guacamole within the image, you can still use them by providing a custom base
+configuration using the `GUACAMOLE_HOME` environment variable:
+
+`GUACAMOLE_HOME`
+: The absolute path to the directory within the Docker container to use *as a
+ template* for the image's automatically-generated [`GUACAMOLE_HOME`](guacamole-home).
+ Any configuration generated by the Guacamole Docker image based on other
+ environment variables will be applied to an independent copy of the contents
+ of this directory.
+
+You will *still* need to follow the steps required to create the contents of
+[`GUACAMOLE_HOME`](guacamole-home) specific to your extension (placing the
+extension itself within `GUACAMOLE_HOME/extensions/`, adding any properties to
+`guacamole.properties`, etc.), but the rest of Guacamole's configuration will
+be handled automatically, overlaid on top of a copy of the `GUACAMOLE_HOME` you
+provide.
+
+Because the Docker image's `GUACAMOLE_HOME` environment variable must point to
+a directory *within the container*, you will need to expose your custom
+`GUACAMOLE_HOME` to the container using the `-v` option of `docker run`. The
+container directory chosen can then be referenced in the `GUACAMOLE_HOME`
+environment variable, and the image will handle the rest automatically:
+
+```console
+$ docker run --name some-guacamole \
+ ...
+ -v /local/path:/some-directory \
+ -e GUACAMOLE_HOME=/some-directory \
+ -d -p 8080:8080 guacamole/guacamole
+```
+
+(verifying-guacamole-docker)=
+
+### Verifying the Guacamole install
+
+Once the Guacamole image is running, Guacamole should be accessible at
+{samp}`http://{HOSTNAME}:8080/guacamole/`, where `HOSTNAME` is the hostname or
+address of the machine hosting Docker, and you *should* see a login screen. If
+using MySQL or PostgreSQL, the database initialization scripts will have
+created a default administrative user called "`guacadmin`" with the password
+"`guacadmin`". *You should log in and change your password immediately.* If
+using LDAP, you should be able to log in as any valid user within your LDAP
+directory.
+
+If you cannot access Guacamole, or you do not see a login screen, check
+Docker's logs using the `docker logs` command to determine if something is
+wrong. Configuration parameters may have been given incorrectly, or the
+database may be improperly initialized:
+
+```console
+$ docker logs some-guacamole
+```
+
diff --git a/src/guacamole-ext.md b/src/guacamole-ext.md
new file mode 100644
index 0000000..bfa2793
--- /dev/null
+++ b/src/guacamole-ext.md
@@ -0,0 +1,693 @@
+guacamole-ext
+=============
+
+While not strictly part of the Java API provided by the Guacamole project,
+guacamole-ext is an API exposed by the Guacamole web application within a
+separate project such that extensions, specifically authentication providers,
+can be written to tweak Guacamole to fit well in existing deployments.
+
+Extensions to Guacamole can:
+
+1. Provide alternative authentication methods and sources of connection/user
+ data.
+
+2. Provide event listeners that will be notified as Guacamole performs tasks
+ such as authentication and tunnel connection.
+
+3. Theme or brand Guacamole through additional CSS files and static resources.
+
+4. Extend Guacamole's JavaScript code by providing JavaScript that will be
+ loaded automatically.
+
+5. Add additional display languages, or alter the translation strings of
+ existing languages.
+
+(ext-file-format)=
+
+Guacamole extension format
+--------------------------
+
+Guacamole extensions are standard Java `.jar` files which contain all classes
+and resources required by the extension, as well as the Guacamole extension
+manifest. There is no set structure to an extension except that the manifest
+must be in the root of the archive. Java classes and packages, if any, will be
+read from the `.jar` relative to the root, as well.
+
+Beyond this, the semantics and locations associated with all other resources
+within the extension are determined by the extension manifest alone.
+
+(ext-manifest)=
+
+### Extension manifest
+
+The Guacamole extension manifest is a single JSON file, `guac-manifest.json`,
+which describes the location of each resource, the type of each resource, and
+the version of Guacamole that the extension was built for. The manifest can
+contain the following properties:
+
+`guacamoleVersion`
+: The version string of the Guacamole release that this extension is written
+ for. *This property is required for all extensions.* The special version
+ string `"*"` can be used if the extension does not depend on a particular
+ version of Guacamole, but be careful - this will bypass version compatibility
+ checks, and should never be used if the extension does more than basic
+ theming or branding.
+
+`name`
+: A human-readable name for the extension. *This property is required for all
+ extensions.* When your extension is successfully loaded, a message
+ acknowledging the successful loading of your extension by name will be
+ logged.
+
+`namespace`
+: A unique string which identifies your extension. *This property is required
+ for all extensions.* This string should be unique enough that it is unlikely
+ to collide with the namespace of any other extension.
+
+ If your extension contains static resources, those resources will be served
+ at a path derived from the namespace provided here.
+
+`authProviders`
+: An array of the classnames of all `AuthenticationProvider` subclasses
+ provided by this extension.
+
+`listeners`
+: An array of the classnames of all `Listener` subclasses provided by this
+ extension.
+
+`js`
+: An array of all JavaScript files within the extension. All paths within this
+ array must be relative paths, and will be interpreted relative to the root of
+ the archive.
+
+ JavaScript files declared here will be automatically loaded when the web
+ application loads within the user's browser.
+
+`css`
+: An array of all CSS files within the extension. All paths within this array
+ must be relative paths, and will be interpreted relative to the root of the
+ archive.
+
+ CSS files declared here will be automatically applied when the web
+ application loads within the user's browser.
+
+`html`
+: An array of all HTML files within the extension that should be used to update
+ or replace existing HTML within the Guacamole interface. All paths within
+ this array must be relative paths, and will be interpreted relative to the
+ root of the archive.
+
+ HTML files declared here will be automatically applied to other HTML within
+ the Guacamole interface when the web application loads within the user's
+ browser. The manner in which the files are applied is dictated by
+ `<meta ...>` tags within those same files.
+
+`translations`
+: An array of all translation files within the extension. All paths within this
+ array must be relative paths, and will be interpreted relative to the root of
+ the archive.
+
+ Translation files declared here will be automatically added to the available
+ languages. If a translation file provides a language that already exists
+ within Guacamole, its strings will override the strings of the existing
+ translation.
+
+`resources`
+: An object where each property name is the name of a web resource file, and
+ each value is the mimetype for that resource. All paths within this object
+ must be relative paths, and will be interpreted relative to the root of the
+ archive.
+
+ Web resources declared here will be made available to the application at
+ {samp}`app/ext/{NAMESPACE}/{PATH}`, where `NAMESPACE` is the value of the
+ namespace property, and `PATH` is the declared web resource filename.
+
+The only absolutely required properties are `guacamoleVersion`, `name`, and
+`namespace`, as they are used to identify the extension and for compatibility
+checks. The most minimal `guac-manifest.json` will look something like this:
+
+```json
+{
+ "guacamoleVersion" : "1.3.0",
+ "name" : "My Extension",
+ "namespace" : "my-extension"
+}
+```
+
+This will allow the extension to load, but does absolutely nothing otherwise.
+Lacking the semantic information provided by the other properties, no other
+files within the extension will be used. A typical `guac-manifest.json` for an
+extension providing theming or branding would be more involved:
+
+```json
+{
+
+ "guacamoleVersion" : "1.3.0",
+
+ "name" : "My Extension",
+ "namespace" : "my-extension",
+
+ "css" : [ "theme.css" ],
+
+ "html" : [ "loginDisclaimer.html" ],
+
+ "resources" : {
+ "images/logo.png" : "image/png",
+ "images/cancel.png" : "image/png",
+ "images/delete.png" : "image/png"
+ }
+
+}
+```
+
+(ext-patch-html)=
+
+### Updating existing HTML
+
+The existing HTML structure of Guacamole's interface can be modified by
+extensions through special "patch" HTML files declared by the html property in
+`guac-manifest.json`. These files are HTML fragments and are identical to any
+other HTML file except that they contain Guacamole-specific meta tags that
+instruct Guacamole to modify its own HTML in a particular way. Each meta tag
+takes the following form:
+
+```html
+<meta name="NAME" content="SELECTOR">
+```
+
+where `SELECTOR` is a CSS selector that matches the elements within the
+Guacamole interface that serve as a basis for the modification, and `NAME` is
+any one of the following defined modifications:
+
+`before`
+: Inserts the specified HTML immediately before any element matching the CSS
+ selector.
+
+`after`
+: Inserts the specified HTML immediately after any element matching the CSS
+ selector.
+
+`replace`
+: Replaces any element matching the CSS selector with the specified HTML.
+
+`before-children`
+: Inserts the specified HTML immediately before the first child (if any) of any
+ element matching the CSS selector. If a matching element has no children, the
+ HTML simply becomes the entire contents of the matching element.
+
+`after-children`
+: Inserts the specified HTML immediately after the last child (if any) of any
+ element matching the CSS selector. If a matching element has no children, the
+ HTML simply becomes the entire contents of the matching element.
+
+`replace-children`
+: Replaces the entire contents of any element matching the CSS selector with
+ the specified HTML.
+
+For example, to add a welcome message and link to some corporate privacy policy
+(a fairly common need), you would add an HTML file like the following:
+
+```html
+<meta name="after" content=".login-ui .login-dialog">
+
+<div class="welcome">
+ <h2>Welcome to our Guacamole server!</h2>
+ <p>
+ Please be sure to read our <a href="/path/to/some/privacy.html">privacy
+ policy</a> before continuing.
+ </p>
+</div>
+```
+
+After the extension is installed and Guacamole is restarted, the "welcome" div
+and its contents will automatically be inserted directly below the login dialog
+(the only element that would match `.login-ui .login-dialog`) as if they were
+part of Guacamole's HTML in the first place.
+
+An example of an extension that modifies style and HTML components for the
+purpose of providing custom "branding" of the Guacamole interface can be found
+in the `doc/guacamole-branding-example` directory of the guacamole-client
+source code, which can be found here:
+<https://github.com/apache/guacamole-client/tree/master/doc/guacamole-branding-example>
+
+(ext-environment)=
+
+Accessing the server configuration
+----------------------------------
+
+The configuration of the Guacamole server is exposed through the `Environment`
+interface, specifically the `LocalEnvironment` implementation of this
+interface. Through `Environment`, you can access all properties declared within
+`guacamole.properties`, determine the proper hostname/port of guacd, and access
+the contents of `GUACAMOLE_HOME`.
+
+(ext-simple-config)=
+
+### Custom properties
+
+If your extension requires generic, unstructured configuration parameters,
+`guacamole.properties` is a reasonable and simple location for them. The
+`Environment` interface provides direct access to `guacamole.properties` and
+simple mechanisms for reading and parsing the properties therein. The value of
+a property can be retrieved by calling `getProperty()`, which will return
+`null` or a default value for undefined properties, or `getRequiredProperty()`,
+which will throw an exception for undefined properties.
+
+For convenience, guacamole-ext contains several pre-defined property base
+classes for common types:
+
+`BooleanGuacamoleProperty`
+: The values "true" and "false" are parsed as their corresponding `Boolean`
+ values. Any other value results in a parse error.
+
+`IntegerGuacamoleProperty`
+: Numeric strings are parsed as `Integer` values. Non-numeric strings will
+ result in a parse error.
+
+`LongGuacamoleProperty`
+: Numeric strings are parsed as `Long` values. Non-numeric strings will result
+ in a parse error.
+
+`StringGuacamoleProperty`
+: The property value is returned as an untouched `String`. No parsing is
+ performed, and parse errors cannot occur.
+
+`FileGuacamoleProperty`
+: The property is interpreted as a filename, and a new `File` pointing to that
+ filename is returned. If the filename is invalid, a parse error will be
+ thrown. Note that the file need not exist or be accessible for the filename
+ to be valid.
+
+To use these types, you must extend the base class, implementing the
+`getName()` function to identify your property. Typically, you would declare
+these properties as static members of some class containing all properties
+relevant to your extension:
+
+```java
+public class MyProperties {
+
+ public static MY_PROPERTY = new IntegerGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "my-property"; }
+
+ };
+
+}
+```
+
+Your property can then be retrieved with `getProperty()` or
+`getRequiredProperty()`:
+
+```java
+Integer value = environment.getProperty(MyProperties.MY_PROPERTY);
+```
+
+If you need more sophisticated parsing, you can also implement your own
+property types by implementing the `GuacamoleProperty` interface. The only
+functions to implement are `getName()`, which returns the name of the property,
+and `parseValue()`, which parses a given string and returns its value.
+
+(ext-advanced-config)=
+
+### Advanced configuration
+
+If you need more structured data than provided by simple properties, you can
+place completely arbitrary files in a hierarchy of your choosing anywhere
+within `GUACAMOLE_HOME` as long as you avoid placing your files in directories
+reserved for other purposes as described above.
+
+The `Environment` interface exposes the location of `GUACAMOLE_HOME` through
+the `getGuacamoleHome()` function. This function returns a standard Java `File`
+which can then be used to locate other files or directories within
+`GUACAMOLE_HOME`:
+
+```java
+File myConfigFile = new File(environment.getGuacamoleHome(), "my-config.xml");
+```
+
+There is no guarantee that `GUACAMOLE_HOME` or your file will exist, and you
+should verify this before proceeding further in your extension's configuration
+process, but once this is done you can simply parse your file as you see fit.
+
+(ext-auth-providers)=
+
+Authentication providers
+------------------------
+
+Guacamole's authentication system is driven by authentication providers, which
+are classes which implement the `AuthenticationProvider` interface defined by
+guacamole-ext. When any page within Guacamole is visited, the following process
+occurs:
+
+1. All currently installed extensions are polled, in lexicographic order of
+ their filenames, by invoking the `getAuthenticatedUser()` function with a
+ `Credentials` object constructed with the contents of the HTTP request.
+
+ The credentials given are abstract. While the `Credentials` object provides
+ convenience access to a traditional username and password, *implementations
+ are not required to use usernames and passwords*. The entire contents of
+ the HTTP request is at your disposal, including parameters, cookies, and SSL
+ information.
+
+2. If an authentication attempt fails, the extension throws either a
+ `GuacamoleInsufficientCredentialsException` (if more credentials are needed
+ before validity can be determined) or `GuacamoleInvalidCredentialsException`
+ (if the credentials are technically sufficient, but are invalid as
+ provided). If all extensions fail to authenticate the user, the contents of
+ the exception thrown by the first extension to fail are used to produce the
+ user login prompt.
+
+ *Note that this means there is no "login screen" in Guacamole per se; the
+ prompt for credentials for unauthenticated users is determined purely based
+ on the needs of the extension as declared within the authentication failure
+ itself.*
+
+ If an authentication attempt succeeds, the extension returns an instance of
+ `AuthenticatedUser` describing the identity of the user that just
+ authenticated, and no further extensions are polled.
+
+3. If authentication has succeeded, and thus an `AuthenticatedUser` is
+ available, that `AuthenticatedUser` is passed to the `getUserContext()`
+ function of all extensions' authentication providers. Each extension now has
+ the opportunity to provide access to data for a user, even if that extension
+ did not originally authenticate the user. If no `UserContext` is returned
+ for the given `AuthenticatedUser`, then that extension has simply refused to
+ provide data for that user.
+
+ The Guacamole interface will transparently unify the data from each
+ extension, providing the user with a view of all available connections. If
+ the user has permission to modify or administer any objects associated with
+ an extension, access to the administrative interface will be exposed as
+ well, again with a unified view of all applicable objects.
+
+:::{important}
+Because authentication is decoupled from data storage/access, *you do not need
+to implement full-blown data storage if you only wish to provide an additional
+authentication mechanism*. You can instead implement only the authentication
+portion of an `AuthenticationProvider`, and otherwise rely on the storage and
+features provided by other extensions, such as the [database authentication
+extension](jdbc-auth).
+:::
+
+The Guacamole web application includes a basic authentication provider
+implementation which parses an XML file to determine which users exist, their
+corresponding passwords, and what configurations those users have access to.
+This is the part of Guacamole that reads the `user-mapping.xml` file. If you
+use a custom authentication provider for your authentication, this file will
+probably not be required.
+
+The community has implemented authentication providers which access databases,
+use LDAP, or even perform no authentication at all, redirecting all users to a
+single configuration specified in `guacamole.properties`.
+
+A minimal authentication provider is implemented in the tutorials later, and
+the upstream authentication provider implemented within Guacamole, as well as
+the authentication providers implemented by the community, are good examples
+for how authentication can be extended without having to implement a whole new
+web application.
+
+(ext-simple-auth)=
+
+### `SimpleAuthenticationProvider`
+
+The `SimpleAuthenticationProvider` class provides a much simpler means of
+implementing authentication when you do not require the ability to add and
+remove users and connections. It is an abstract class and requires only one
+function implementation: `getAuthorizedConfigurations()`.
+
+This function is required to return a `Map` of unique IDs to configurations,
+where these configurations are all configurations accessible with the provided
+credentials. As before, the credentials given are abstract. You are not
+required to use usernames and passwords.
+
+The configurations referred to by the function name are instances of
+`GuacamoleConfiguration` (part of guacamole-common), which is just a wrapper
+around a protocol name and set of parameter name/value pairs. The name of the
+protocol to use and a set of parameters is the minimum information required for
+other parts of the Guacamole API to complete the handshake required by the
+Guacamole protocol.
+
+When a class that extends `SimpleAuthenticationProvider` is asked for more
+advanced operations by the web application, `SimpleAuthenticationProvider`
+simply returns that there is no permission to do so. This effectively disables
+all administrative functionality within the web interface.
+
+If you choose to go the simple route, most of the rest of this chapter is
+irrelevant. Permissions, security model, and various classes will be discussed
+that are all handled for you automatically by `SimpleAuthenticationProvider`.
+
+(ext-user-context)=
+
+The `UserContext`
+-----------------
+
+The `UserContext` is the root of all data-related operations. It is used to
+list, create, modify, or delete users and connections, as well as to query
+available permissions. If an extension is going to provide access to data of
+any sort, it must do so through the `UserContext`.
+
+The Guacamole web application uses permissions queries against the
+`UserContext` to determine what operations to present, but *beware that it is
+up to the `UserContext` to actually enforce these restrictions*. The Guacamole
+web application will not enforce restrictions on behalf of the `UserContext`.
+
+The `UserContext` is the sole means of entry and the sole means of modification
+available to a logged-in user. If the `UserContext` refuses to perform an
+operation (by throwing an exception), the user cannot perform the operation at
+all.
+
+(ext-object-directories)=
+
+`Directory` classes
+-------------------
+
+Access to objects beneath the `UserContext` is given through `Directory`
+classes. These `Directory` classes are similar to Java collections, but they
+also embody update and batching semantics. Objects can be retrieved from a
+`Directory` using its `get()` function and added or removed with `add()` and
+`remove()` respectively, but objects already in the set can also be updated by
+passing an updated object to its `update()` function.
+
+An implementation of a `Directory` can rely on these functions to define the
+semantics surrounding all operations. The `add()` function is called only when
+creating new objects, the `update()` function is called only when updating an
+object previously retrieved with `get()`, and `remove()` is called only when
+removing an existing object by its identifier.
+
+When implementing an `AuthenticationProvider`, you must ensure that the
+`UserContext` will only return `Directory` classes that automatically enforce
+the permissions associated with all objects and the associated user.
+
+(ext-rest-resources)=
+
+REST resources
+--------------
+
+Arbitrary REST resources may be exposed by extensions at the
+`AuthenticationProvider` level, if the resource does not require an associated
+authenticated user, or at the `UserContext` level, if the resource should be
+available to authenticated users only. In both cases, the REST resource is
+provided through implementing the `getResource()` function, returning an object
+which is annotated with JAX-RS annotations (JSR 311).
+
+The resource returned by `getResource()` functions as the root resource,
+providing access to other resources beneath itself. The root resource for the
+`AuthenticationProvider` is exposed at {samp}`{PATH}/api/ext/{IDENTIFIER}`, and
+the root resource for the `UserContext` is exposed at
+{samp}`{PATH}/api/session/ext/{IDENTIFIER}`, where `PATH` is the path to which
+Guacamole has been deployed (typically `/guacamole/`) and `IDENTIFIER` is the
+unique identifier for the `AuthenticationProvider`, as returned by
+`getIdentifier()`.
+
+The behavior of extension REST resources is generally left entirely to the
+implementation, with the exception that the "token" request parameter is
+reserved for use by Guacamole. This parameter contains the user's
+authentication token when the user is logged in, and must be present on all
+requests which require authentication. Though not relevant to REST resources
+exposed at the `AuthenticationProvider` level, resources exposed at the
+`UserContext` level inherently require the "token" parameter to be present, as
+it is the sole means of locating the user's session.
+
+(ext-permissions)=
+
+Permissions
+-----------
+
+The permissions system within guacamole-ext is an advisory system. It is the
+means by which an authentication module describes to the web application what a
+user is allowed to do. The body of permissions granted to a user describes
+which objects that user can see and what they can do to those objects, and thus
+suggests how the Guacamole interface should appear to that user.
+
+*Permissions are not the means by which access is restricted*; they are purely
+a means of describing access level. An implementation may internally use the
+permission objects to define restrictions, but this is not required. It is up
+to the implementation to enforce its own restrictions by throwing exceptions
+when an operation is not allowed, and to correctly communicate the abilities of
+individual users through these permissions.
+
+The permissions available to a user are exposed through the
+`SystemPermissionSet` and `ObjectPermissionSet` classes which are accessible
+through the `UserContext`. These classes also serve as the means for
+manipulating the permissions granted to a user.
+
+### System permissions
+
+System permissions describe access to operations that manipulate the system as
+a whole, rather than specific objects. This includes the creation of new
+objects, as object creation directly affects the system, and per-object
+controls cannot exist before the object is actually created.
+
+`ADMINISTER`
+: The user is a super-user - the Guacamole equivalent of root. They are allowed
+ to manipulate of system-level permissions and all other objects. This
+ permission implies all others.
+
+`CREATE_CONNECTION`
+: The user is allowed to create new connections. If a user has this permission,
+ the management interface will display components related to connection
+ creation.
+
+`CREATE_CONNECTION_GROUP`
+: The user is allowed to create new connection groups. If a user has this
+ permission, the management interface will display components related to
+ connection group creation.
+
+`CREATE_SHARING_PROFILE`
+: The user is allowed to create new sharing profiles. If a user has this
+ permission, the management interface will display components related to
+ sharing profile creation.
+
+`CREATE_USER`
+: The user is allowed to create other users. If a user has this permission, the
+ management interface will display components related to user creation.
+
+### Object permissions
+
+Object permissions describe access to operations that affect a particular
+object. Guacamole currently defines four types of objects which can be
+associated with permissions: users, connections, connection groups, and sharing
+profiles. Each object permission associates a single user with an action that
+may be performed on a single object.
+
+`ADMINISTER`
+: The user may grant or revoke permissions involving this object. "Involving",
+ in this case, refers to either side of the permission association, and
+ includes both the user to whom the permission is granted and the object the
+ permission affects.
+
+`DELETE`
+: The user may delete this object. This is distinct from the `ADMINISTER`
+ permission which deals only with permissions. A user with this permission
+ will see the "Delete" button when applicable.
+
+`READ`
+: The user may see that this object exists and read the properties of that
+ object.
+
+ Note that the implementation is *not required to divulge the true underlying
+ properties of any object*. The parameters of a connection or sharing profile,
+ the type or contents of a connection group, the password of a user, etc. all
+ need not be exposed.
+
+ This is particularly important from the perspective of security when it comes
+ to connections, as the parameters of a connection are only truly needed when
+ a connection is being modified, and likely should not be exposed otherwise.
+ The actual connection operation is always performed internally by the
+ authentication provider, and thus does not require client-side knowledge of
+ anything beyond the connection's existence.
+
+`UPDATE`
+: The user may change the properties of this object.
+
+ In the case of users, this means the user's password can be altered.
+ *Permissions are not considered properties of a user*, nor objects in their
+ own right, but rather associations between a user and an action which may
+ involve another object.
+
+ The properties of a connection include its name, protocol, parent connection
+ group, and parameters. The properties of a connection group include its name,
+ type, parent connection group, and children. The properties of a sharing
+ profile include its name, primary connection, and parameters.
+
+(ext-connections)=
+
+Connections
+-----------
+
+Guacamole connections are organized in a hierarchy made up of connection
+groups, which each act as folders organizing the connections themselves. The
+hierarchy is accessed through the root-level connection group, exposed by
+`getRootConnectionGroup()` by the `UserContext`. The connections and connection
+groups exposed beneath the root connection group must also be accessible
+directly through the connection and connection group directories exposed by
+`getConnectionDirectory()` and `getConnectionGroupDirectory()` of the
+`UserContext`.
+
+When a user attempts to use a connection the `connect()` of the associated
+`Connection` object will be invoked. It is then up to the implementation of
+this function to establish the TCP connection to guacd, perform the connection
+handshake (most likely via an `InetGuacamoleSocket` wrapped within a
+`ConfiguredGuacamoleSocket`), and then return a `GuacamoleTunnel` which
+controls access to the established socket.
+
+Extensions may maintain historical record of connection use via
+`ConnectionRecord` objects, which are exposed both at the `Connection` level
+and across all connections via the `UserContext`. Such record maintenance is
+optional, and it is expected that most implementations will simply return empty
+lists.
+
+:::{important}
+If connection state will not be tracked by the extension, and the parameters
+associated with the connection will be known at the time the connection object
+is created, the `SimpleConnection` implementation of `Connection` can be used
+to make life easier.
+:::
+
+(ext-active-connections)=
+
+Managing/sharing active connections
+-----------------------------------
+
+After a connection has been established, its underlying `GuacamoleTunnel` can
+be exposed by a `UserContext` through the `Directory` returned by
+getActiveConnectionDirectory(). The `ActiveConnection` objects accessible
+through this `Directory` are the means by which an administrator may monitor or
+forcibly terminate another user's connection, ultimately resulting in Guacamole
+invoking the `close()` function of the underlying `GuacamoleTunnel`, and also
+serve as the basis for screen sharing.
+
+Screen sharing is implemented through the use of `SharingProfile` objects,
+exposed through yet another `Directory` beneath the `UserContext`. Each sharing
+profile is associated with a single connection that it can be used to share,
+referred to as the "primary connection". If a user has read access to a sharing
+profile associated with their current connection, that sharing profile will be
+displayed as an option within [the share menu of the Guacamole
+menu](client-share-menu).
+
+The overall sharing process is as follows:
+
+1. A user, having access to a sharing profile associated with their current
+ active connection, clicks its option within the [share menu](client-share-menu).
+
+2. Guacamole locates the `ActiveConnection` and invokes its
+ `getSharingCredentials()` function with the identifier of the sharing
+ profile. The contents of the returned `UserCredentials` object is used by
+ Guacamole to generate a sharing link which can be given to other users.
+
+3. When another user visits the sharing link, the credentials embedded in the
+ link are passed to the authentication providers associated with each
+ installed extension. *It is up to the extension that originally provided
+ those credentials to authenticate the user and provide them with access to
+ the shared connection.*
+
+4. When the user attempts to connect to the shared connection, the extension
+ establishes the connection using the ID of the connection being joined.
+ *This is not the connection identifier as dictated by guacamole-ext, but
+ rather [the unique ID assigned by guacd as required by the Guacamole
+ protocol](guacamole-protocol-joining).* This ID can be retrieved from a
+ `ConfiguredGuacamoleSocket` via `getConnectionID()`, and can be passed
+ through a `GuacamoleConfiguration` through `setConnectionID()` (instead of
+ specifying a protocol, as would be done for a brand new connection).
+
diff --git a/src/guacamole-protocol.md b/src/guacamole-protocol.md
new file mode 100644
index 0000000..1ec2dc6
--- /dev/null
+++ b/src/guacamole-protocol.md
@@ -0,0 +1,405 @@
+The Guacamole protocol
+======================
+
+This chapter is an overview of the Guacamole protocol, describing its design
+and general use. While a few instructions and their syntax will be described
+here, this is not an exhaustive list of all available instructions. The intent
+is only to list the general types and usage. If you are looking for the syntax
+or purpose of a specific instruction, consult the protocol reference included
+with the appendices.
+
+(guacamole-protocol-design)=
+
+Design
+------
+
+The Guacamole protocol consists of instructions. Each instruction is a
+comma-delimited list followed by a terminating semicolon, where the first
+element of the list is the instruction opcode, and all following elements are
+the arguments for that instruction:
+
+```
+OPCODE,ARG1,ARG2,ARG3,...;
+```
+
+Each element of the list has a positive decimal integer length prefix separated
+by the value of the element by a period. This length denotes the number of
+Unicode characters in the value of the element, which is encoded in UTF-8:
+
+```
+LENGTH.VALUE
+```
+
+Any number of complete instructions make up a message which is sent from client
+to server or from server to client. Client to server instructions are generally
+control instructions (for connecting or disconnecting) and events (mouse and
+keyboard). Server to client instructions are generally drawing instructions
+(caching, clipping, drawing images), using the client as a remote display.
+
+For example, a complete and valid instruction for setting the display size to
+1024x768 would be:
+
+```
+4.size,1.0,4.1024,3.768;
+```
+
+Here, the instruction would be decoded into four elements: "size", the opcode
+of the size instruction, "0", the index of the default layer, "1024", the
+desired width in pixels, and "768", the desired height in pixels.
+
+The structure of the Guacamole protocol is important as it allows the protocol
+to be streamed while also being easily parsable by JavaScript. JavaScript does
+have native support for conceptually-similar structures like XML or JSON, but
+neither of those formats is natively supported in a way that can be streamed;
+JavaScript requires the entirety of the XML or JSON message to be available at
+the time of decoding. The Guacamole protocol, on the other hand, can be parsed
+as it is received, and the presence of length prefixes within each instruction
+element means that the parser can quickly skip around from instruction to
+instruction without having to iterate over every character.
+
+(guacamole-protocol-handshake)=
+
+Handshake phase
+---------------
+
+The handshake phase is the phase of the protocol entered immediately upon
+connection. It begins with a "select" instruction sent by the client which
+tells the server which protocol will be loaded:
+
+```
+6.select,3.vnc;
+```
+
+After receiving the "select" instruction, the server will load the associated
+client support and respond with its protocol version and a list of accepted
+parameter names using an "args" instruction:
+
+```
+4.args,13.VERSION_1_1_0,8.hostname,4.port,8.password,13.swap-red-blue,9.read-only;
+```
+
+The protocol version is used to negotiate compatibility between differing
+versions of client and server, allowing the two sides to negotiate the highest
+supported version and enable or disable features associated with that version.
+Older implementations of the Guacamole protocol that do not support version
+negotiation will silently ignore it as if it were an unspecified connection
+parameter.
+
+Valid protocol versions are as follows:
+
+`VERSION_1_3_0`
+: Protocol version 1.3.0 introduced the `require` instruction, used by the
+ server to indicate that the client must provide additional arguments (such
+ as a username and password).
+
+`VERSION_1_1_0`
+: Protocol version 1.1.0 introduced support for protocol version
+ negotiation, arbitrary order of the handshake instructions, and support
+ for passing the timezone instruction during the handshake.
+
+`VERSION_1_0_0`
+: This is the default version and applies to any versions prior to 1.1.0.
+ Version 1.0.0 of the protocol does not support protocol negotiation, and
+ requires that the handshake instructions are delivered in a certain order,
+ and that they are present (even if empty).
+
+After receiving the list of arguments, the client is required to respond with
+the list of supported audio, video, and image mimetypes, the optimal display
+size and resolution, and the values for all arguments available, even if blank.
+
+```
+4.size,4.1024,3.768,2.96;
+5.audio,9.audio/ogg;
+5.video;
+5.image,9.image/png,10.image/jpeg;
+8.timezone,16.America/New_York;
+7.connect,13.VERSION_1_1_0,9.localhost,4.5900,0.,0.,0.;
+```
+
+For clarity, we've put each instruction on its own line, but in the real
+protocol, no newlines exist between instructions. In fact, if there is anything
+after an instruction other than the start of a new instruction, the connection
+is closed.
+
+The following are valid instructions during the handshake:
+
+`audio`
+: The audio codec(s) supported by the client. In the example above the
+ client is specifying audio/ogg as the supported codec.
+
+`connect`
+: This is the final instruction of the handshake, terminating the handshake
+ and indicating that the connection should continue. This instruction has
+ as its parameters values for the connection parameters sent by the server
+ in the `args` instruction. In the example above, this is connection to
+ localhost on port 5900, with no values for the last three connection
+ parameters.
+
+`image`
+: The image formats that the client supports, in order of preference. The
+ client in the example above is supporting both PNG and JPEG.
+
+`timezone`
+: The timezone of the client, in IANA zone key format. More information on
+ this instruction is available in [](configuring-guacamole), under
+ documentation related to the `timezone` connection parameters for the
+ protocols that support it.
+
+`video`
+: The video codec(s) supported by the client. The above example is a client
+ that does not support any video codecs.
+
+The order of the instructions sent by the client in the handshake is arbitrary,
+with the exception that the final instruction, connect, will end the handshake
+and attempt to start the connection.
+
+Once these instructions have been sent by the client, the server will attempt
+to initialize the connection with the parameters received and, if successful,
+respond with a "ready" instruction. This instruction contains the ID of the new
+client connection and marks the beginning of the interactive phase. The ID is
+an arbitrary string, but is guaranteed to be unique from all other active
+connections, as well as from the names of all supported protocols:
+
+```
+5.ready,37.$260d01da-779b-4ee9-afc1-c16bae885cc7;
+```
+
+The actual interactive phase begins immediately after the "ready" instruction
+is sent. Drawing and event instructions pass back and forth until the
+connection is closed.
+
+(guacamole-protocol-joining)=
+
+### Joining an existing connection
+
+Once the handshake phase has completed, that connection is considered active
+and can be joined by other connections if the ID is provided instead of a
+protocol name via the "select" instruction:
+
+```
+6.select,37.$260d01da-779b-4ee9-afc1-c16bae885cc7;
+```
+
+The rest of the handshake phase for a joining connection is identical. Just as
+with a new connection, the restrictions or features which apply to the joining
+connection are dictated by the parameter values supplied during the handshake.
+
+(guacamole-protocol-drawing)=
+
+Drawing
+-------
+
+(guacamole-protocol-compositing)=
+
+### Compositing
+
+The Guacamole protocol provides compositing operations through the use of
+"channel masks". The term "channel mask" is simply a description of the
+mechanism used while designing the protocol to conceptualize and fully
+enumerate all possible compositing operations based on four different sources
+of image data: source image data where the destination is opaque, source image
+data where the destination is transparent, destination image data where the
+source is opaque, and destination image data where the source is transparent.
+Assigning a binary value to each of these "channels" creates a unique integer
+ID for every possible compositing operation, where these operations parallel
+the operations described by Porter and Duff in their paper. As the HTML5 canvas
+tag also uses Porter/Duff to describe their compositing operations (as do other
+graphical APIs), the Guacamole protocol is conveniently similar to the
+compositing support already present in web browsers, with some operations not
+yet supported. The following operations are all implemented and known to work
+correctly in all browsers:
+
+B out A (0x02)
+: Clears the destination where the source is opaque, but otherwise draws
+ nothing. This is useful for masking.
+
+A atop B (0x06)
+: Fills with the source where the destination is opaque only.
+
+A xor B (0x0A)
+: As with logical XOR. Note that this is a compositing operation, not a
+ bitwise operation. It draws the source where the destination is
+ transparent, and draws the destination where the source is transparent.
+
+B over A (0x0B)
+: What you would typically expect when drawing, but reversed. The source
+ appears only where the destination is transparent, as if you were
+ attempting to draw the destination over the source, rather than the source
+ over the destination.
+
+A over B (0x0E)
+: The most common and sensible compositing operation, this draws the source
+ everywhere, but includes the destination where the source is transparent.
+
+A + B (0x0F)
+: Simply adds the components of the source image to the destination image,
+ capping the result at pure white.
+
+The following operations are all implemented, but may work incorrectly in
+WebKit browsers which always include the destination image where the source is
+transparent:
+
+B in A (0x01)
+: Draws the destination only where the source is opaque, clearing anywhere
+ the source or destination are transparent.
+
+A in B (0x04)
+: Draws the source only where the destination is opaque, clearing anywhere
+ the source or destination are transparent.
+
+A out B (0x08)
+: Draws the source only where the destination is transparent, clearing
+ anywhere the source or destination are opaque.
+
+B atop A (0x09)
+: Fills with the destination where the source is opaque only.
+
+A (0x0C)
+: Fills with the source, ignoring the destination entirely.
+
+The following operations are defined, but not implemented, and do not exist as
+operations within the HTML5 canvas:
+
+Clear (0x00)
+: Clears all existing image data in the destination.
+
+B (0x03)
+: Does nothing.
+
+A xnor B (0x05)
+: Adds the source to the destination where the destination or source are
+ opaque, clearing anywhere the source or destination are transparent. This
+ is similar to A + B except the aspect of transparency is also additive.
+
+(A + B) atop B (0x07)
+: Adds the source to the destination where the destination is opaque,
+ preserving the destination otherwise.
+
+(A + B) atop A (0x0D)
+: Adds the destination to the source where the source is opaque, copying the
+ source otherwise.
+
+(guacamole-protocol-images)=
+
+### Image data
+
+The Guacamole protocol, like many remote desktop protocols, provides a method
+of sending an arbitrary rectangle of image data and placing it either within a
+buffer or in a visible rectangle of the screen. Raw image data in the Guacamole
+protocol is streamed as PNG, JPEG, or WebP data over a stream allocated with
+the "img" instruction. Depending on the format used, image updates sent in this
+manner can be RGB or RGBA (alpha transparency) and are automatically palettized
+if sent using libguac. The streaming system used for image data is generalized
+and used by Guacamole for other types of streams, including audio and file
+transfer. For more information about streams in the Guacamole protocol, see
+[](guacamole-protocol-streaming).
+
+Image data can be sent to any specified rectangle within a layer or buffer.
+Sending the data to a layer means that the image becomes immediately visible,
+while sending the data to a buffer allows that data to be reused later.
+
+(guacamole-protocol-copying-images)=
+
+### Copying image data between layers
+
+Image data can be copied from one layer or buffer into another layer or buffer.
+This is often used for scrolling (where most of the result of the graphical
+update is identical to the previous state) or for caching parts of an image.
+
+Both VNC and RDP provide a means of copying a region of screen data and placing
+it somewhere else within the same screen. RDP provides an additional means of
+copying data to a cache, or recalling data from that cache and placing it on
+the screen. Guacamole takes this concept and reduces it further, as both
+on-screen and off-screen image storage is the same. The Guacamole "copy"
+instruction allows you to copy a rectangle of image data, and place it within
+another layer, whether that layer is the same as the source layer, a different
+visible layer, or an off-screen buffer.
+
+(guacamole-graphical-primitives)=
+
+### Graphical primitives
+
+The Guacamole protocol provides basic graphics operations similar to those of
+Cairo or the HTML5 canvas. In many cases, these primitives are useful for
+remote drawing, and desirable in that they take up less bandwidth than sending
+corresponding PNG images. Beware that excessive use of primitives leads to an
+increase in client-side processing, which may reduce the performance of a
+connected client, especially if that client is on a lower-performance machine
+like a mobile phone or tablet.
+
+(guacamole-protocol-layers)=
+
+### Buffers and layers
+
+All drawing operations in the Guacamole protocol affect a layer, and each layer
+has an integer index which identifies it. When this integer is negative, the
+layer is not visible, and can be used for storage or caching of image data. In
+this case, the layer is referred to within the code and within documentation as
+a "buffer". Layers are created automatically when they are first referenced in
+an instruction.
+
+There is one main layer which is always present called the "default layer".
+This layer has an index of 0. Resizing this layer resizes the entire remote
+display. Other layers default to the size of the default layer upon creation,
+while buffers are always created with a size of 0x0, automatically resizing
+themselves to fit their contents.
+
+Non-buffer layers can be moved and nested within each other. In this way,
+layers provide a simple means of hardware-accelerated compositing. If you need
+a window to appear above others, or you have some object which will be moving
+or you need the data beneath it automatically preserved, a layer is a good way
+of accomplishing this. If a layer is nested within another layer, its position
+is relative to that of its parent. When the parent is moved or reordered, the
+child moves with it. If the child extends beyond the parents bounds, it will
+be clipped.
+
+(guacamole-protocol-streaming)=
+
+Streams and objects
+-------------------
+
+Guacamole supports transfer of clipboard contents, audio, video, and image
+data, as well as files and arbitrary named pipes.
+
+Streams are allocated directly with instructions that associate the new stream
+with particular semantics and metadata, such as the "audio" or "video"
+instructions used for playing media, the "file" instruction used for file
+transfer, and the "pipe" instruction for transfer of completely arbitrary data
+between client and server. In some cases, the availability and semantics of
+streams may be explicitly advertised using structured sets of named streams
+known as "objects".
+
+Once a stream is allocated, data is sent along the stream in chunks using
+"blob" instructions, which may be acknowledged by the receiving end by "ack"
+instructions. The end of the stream is finally signalled with an "end"
+instruction.
+
+(guacamole-protocol-events)=
+
+Events
+------
+
+When something changes on either side, client or server, such as a key being
+pressed, the mouse moving, or clipboard data changing, an instruction
+describing the event is sent.
+
+(guacamole-protocol-disconnecting)=
+
+Disconnecting
+-------------
+
+The server and client can end the connection at any time. There is no
+requirement for the server or the client to communicate that the connection
+needs to terminate. When the client or server wish to end the connection, and
+the reason is known, they can use the "disconnect" or "error" instructions.
+
+The disconnect instruction is sent by the client when it is disconnecting. This
+is largely out of politeness, and the server must be written knowing that the
+disconnect instruction may not always be sent in time (guacd is written this
+way).
+
+If the client does something wrong, or the server detects a problem with the
+client plugin, the server sends an error instruction, including a description
+of the problem in the parameters. This informs the client that the connection
+is being closed.
+
diff --git a/src/gug.css b/src/gug.css
deleted file mode 100644
index 370de3e..0000000
--- a/src/gug.css
+++ /dev/null
@@ -1,179 +0,0 @@
-
-body {
-
- color: black;
- background: white;
-
- font-family: 'FreeSans', 'Liberation Sans', 'Arial', 'Helvetica', sans-serif;
- text-align: justify;
- text-rendering: optimizeLegibility;
- line-height: 125%;
-
- margin: 0;
- padding: 0;
-
-}
-
-/* Green links */
-a[href] { color: #080; }
-a[href]:visited { color: #884; }
-
-div#content {
-
- margin-top: 0;
- margin-bottom: 0;
- margin-left: auto;
- margin-right: auto;
-
- max-width: 25cm;
- padding: 1em;
-
-}
-
-/* DOCBOOK */
-
-.navheader hr, .navfooter hr {
- border: 0;
- border-bottom: 1px solid black;
-}
-
-.chapter div.toc,
-.appendix div.toc {
- border: 1px solid #BCBCBC;
- background: #FBFBFB;
- margin: 2em;
- padding: 0 1em;
- font-size: 0.75em;
-}
-
-.programlisting, .screen {
- padding: 1em;
-}
-
-.replaceable {
- color: #008;
- background: rgba(0, 0, 0, 0.05);
- border: 1px solid rgba(0, 0, 0, 0.05);
- font-style: normal;
- padding: 0 0.25em;
-}
-
-pre .emphasis em {
- font-style: normal;
- font-weight: bold;
-}
-
-.book .titlepage {
- text-align: center;
- padding: 2em;
-}
-
-.titlepage hr {
- display: none;
-}
-
-.titlepage .legalnotice {
- text-align: left;
-}
-
-.mediaobject {
- text-align: center;
- float: none;
- margin: 1em;
-}
-
-.mediaobject img {
- width: auto;
- max-width: 100%;
-}
-
-.screenshot img {
- border: 1px solid black;
-}
-
-.caption {
- font-size: 0.8em;
- font-style: italic;
-}
-
-.navfooter, .section {
- clear: both;
-}
-
-.table-contents, .informaltable {
- margin: 1em;
-}
-
-.table-contents table,
-.informaltable table {
- border: 1px solid #BCBCBC;
- border-collapse: collapse;
- font-size: 10pt;
-}
-
-.table-contents th, .informaltable th {
- background: #FBFBFB;
-}
-
-.table-contents td, .table-contents th,
-.informaltable td, .informaltable th {
- border: 1px solid #BCBCBC;
- padding: 0.5em;
- min-width: 1.5in;
-}
-
-.table-contents table table,
-.informaltable table table {
- border: none;
-}
-
-.table-contents table table td,
-.table-contents table table th,
-.informaltable table table td,
-.informaltable table table th {
- background: none;
- padding: 0.25em;
-}
-
-dl.variablelist {
- margin-left: 1em;
-}
-
-.variablelist .term {
- font-weight: bold;
-}
-
-blockquote {
- border-left: 1px solid rgba(0, 0, 0, 0.25);
- padding: 1px 1em;
- font-style: oblique;
- color: rgba(0, 0, 0, 0.75);
-}
-
-div.important {
- background: #FFFFE8;
- border: 1px solid rgba(0, 0, 0, 0.25);
- padding: 0 1em;
- margin: 2em;
-}
-
-/* Printable styles */
-
-@media print {
-
- .navheader, .navfooter, .chapter .toc {
- display: none
- }
-
- body {
- font-size: 10pt;
- }
-
- .chapter > .titlepage {
- margin: 2em 0;
- font-size: 1.5em;
- text-align: center;
- }
-
-}
-
diff --git a/src/gug.xml b/src/gug.xml
deleted file mode 100644
index 2dbe1fb..0000000
--- a/src/gug.xml
+++ /dev/null
@@ -1,193 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<book xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <info>
- <title>Guacamole Manual</title>
- <edition>1.3.0</edition>
- <legalnotice>
- <para>Licensed to the Apache Software Foundation (ASF) under one or more contributor
- license agreements. See the <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://raw.githubusercontent.com/apache/guacamole-manual/master/NOTICE"
- ><filename>NOTICE</filename></link> file distributed with this work for
- additional information regarding copyright ownership. The ASF licenses this file to
- you under the Apache License, Version 2.0 (the "License"); you may not use this file
- except in compliance with the License. You may obtain a copy of the License
- at:</para>
- <para><link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="http://www.apache.org/licenses/LICENSE-2.0"
- ><uri>http://www.apache.org/licenses/LICENSE-2.0</uri></link></para>
- <para>Unless required by applicable law or agreed to in writing, software distributed
- under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
- language governing permissions and limitations under the License.</para>
- </legalnotice>
- </info>
- <preface xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="preface">
- <title>Introduction</title>
- <para>This book is the official Apache Guacamole manual, written by the upstream developers
- of the Guacamole project. It is also the official general documentation, and an online
- version at <link xlink:href="http://guacamole.apache.org/"
- >http://guacamole.apache.org/</link>. It is a work in progress which will
- be continuously updated as Guacamole changes with each release.</para>
- <para>We decided to maintain the documentation for Guacamole as a book, as there is an awful
- lot that can be done with the Guacamole web application, and even more that can be done
- with the API. This book is intended to explore the possibilities of Guacamole as an
- application, and to provide documentation necessary to install, maintain, and use
- Guacamole.</para>
- <para>For the sake of users and administrators, we have provided a high-level overview of
- Guacamole's architecture and technical design, as well as basic usage instructions and
- installation instructions for common platforms.</para>
- <para>For the sake of developers, we have provided a protocol reference and tutorials for
- common tasks (implementing protocol support, integrating Guacamole into your own
- application, etc.) to give a good starting point beyond simply looking at the Guacamole
- codebase.</para>
- <para>This particular edition of the <citetitle>Guacamole Manual</citetitle> covers
- Guacamole version 1.3.0. New releases which create new features or break
- compatibility will result in new editions of the user's guide, as will any necessary
- corrections. As the official documentation for the project, this book will always be
- freely available in its entirety online.</para>
- <indexterm>
- <primary>Guacamole</primary>
- <secondary>history</secondary>
- </indexterm>
- <simplesect xml:id="what-is-guac">
- <title>What is Guacamole?</title>
- <indexterm>
- <primary>Guacamole</primary>
- <secondary>definition</secondary>
- </indexterm>
- <para>Guacamole is an HTML5 web application that provides access to desktop environments
- using remote desktop protocols (such as VNC or RDP). Guacamole is also the project
- that produces this web application, and provides an API that drives it. This API can
- be used to power other similar applications or services.</para>
- <para>"Guacamole" is most commonly used to refer to the web application produced by the
- Guacamole project using their API. This web application is part of a stack that
- provides a protocol-agnostic remote desktop gateway. Written in JavaScript and using
- only HTML5 and other standards, the client part of Guacamole requires nothing more
- than a modern web browser or web-enabled device when accessing any of the desktops
- served.</para>
- <indexterm>
- <primary>RealMint</primary>
- </indexterm>
- <para>Historically, Guacamole was an HTML5 VNC client, and before that, a JavaScript
- Telnet client called <application
- xlink:href="http://sourceforge.net/projects/realmint">RealMint</application>
- ("RealMint" is an anagram for "terminal"), but this is no longer the case.
- Guacamole's architecture has grown to encompass remote desktop in general, and can
- be used as a gateway for any number of computers. Originally a proof-of-concept,
- Guacamole is now performant enough for daily use, and all Guacamole development is
- done over Guacamole.</para>
- <para>As an API, Guacamole provides a common and efficient means of streaming text data
- over a JavaScript-based tunnel using either HTTP or WebSocket, and a client
- implementation which supports the Guacamole protocol and renders the remote display
- when combined with a Guacamole protocol stream from the tunnel.</para>
- <para>It provides cross-browser mouse and keyboard events, an XML-driven on-screen
- keyboard, and synchronized nestable layers with hardware-accelerated compositing.
- Projects that wish to provide remote desktop support over HTML5 can leverage the
- years of research and development that went into Guacamole by incorporating the API
- into their application or service.</para>
- </simplesect>
- <simplesect xml:id="access-from-anywhere" xmlns:xl="http://www.w3.org/1999/xlink">
- <title>Why use Guacamole?</title>
- <para>The principle reason to use Guacamole is constant, world-wide, unfettered access
- to your computers.</para>
- <para>Guacamole allows access one or more desktops from anywhere remotely, without
- having to install a client, particularly when installing a client is not possible.
- By setting up a Guacamole server, you can provide access to any other computer on
- the network from virtually any other computer on the internet, anywhere in the
- world. Even mobile phones or tablets can be used, without having to install
- anything.</para>
- <para>As a true web application whose communication is over HTTP or HTTPS only,
- Guacamole allows you to access your machines from anywhere without violating the
- policy of your workplace, and without requiring the installation of special clients.
- The presence of a proxy or corporate firewall does not prevent Guacamole use.</para>
- </simplesect>
- <simplesect xml:id="access-from-anything" xmlns:xl="http://www.w3.org/1999/xlink">
- <title>Access your computers from any device</title>
- <para>As Guacamole requires only a reasonably-fast, standards-compliant browser,
- Guacamole will run on many devices, including mobile phones and tablets.</para>
- <para>Guacamole is specifically designed to not care whether you have a mouse, keyboard,
- touchscreen, or any combination of those.</para>
- <para>One of the major design philosophies behind Guacamole is that it should never
- assume you have a particular device (ie: a mobile phone) just because your browser
- has or is missing a specific feature (ie: touch events or a smallish screen).
- Guacamole's codebase provides support for both mouse and touch events
- simultaneously, without choosing one over the other, while the interface is intended
- to be usable regardless of screen size.</para>
- <para>Barring bugs, you should be able to use Guacamole on just about any modern device
- with a web browser.</para>
- </simplesect>
- <simplesect xml:id="non-physical-computer" xmlns:xl="http://www.w3.org/1999/xlink">
- <title>Keep a computer in the "cloud"</title>
- <para>Ignoring the buzzword, it's often useful to have a computer that has no dedicated
- physical hardware, where its processing and storage power are handled transparently
- by redundant systems in some remote datacenter.</para>
- <para>Computers hosted on virtualized hardware are more resilient to failures, and with
- so many companies now offering on-demand computing resources, Guacamole is a perfect
- way to access several machines that are only accessible over the internet.</para>
- <para>In fact, all Guacamole development is done on computers like this. This is partly
- because we like the mobility, and partly because we want to ensure Guacamole is
- always performant enough for daily use.</para>
- </simplesect>
- <simplesect xml:id="group-access" xmlns:xl="http://www.w3.org/1999/xlink">
- <title>Provide easy access to a group</title>
- <para>Guacamole allows you to centralize access to a large group of machines, and
- specify on a per-user basis which machines are accessible. Rather than remember a
- list of machines and credentials, users need only log into a central server and
- click on one of the connections listed.</para>
- <para>If you have multiple computers which you would like to access remotely, or you are
- part of a group where each person has a set of machines that they need remote access
- to, Guacamole is a good way to provide that access while also ensuring that access
- is available from anywhere.</para>
- </simplesect>
- <simplesect xml:id="adding-remote-access" xmlns:xl="http://www.w3.org/1999/xlink">
- <title>Adding HTML5 remote access to your existing infrastructure</title>
- <para>As Guacamole is an API, not just a web application, the core components and
- libraries provided by the Guacamole project can be used to add HTML5 remote access
- features to an existing application. You need not use the main Guacamole web
- application; you can write (or integrate with) your own rather easily.</para>
- <para>If you host an on-demand computing service, adding HTML5-based remote access
- allows users of your service more broad access; users need nothing more than a web
- browser to see their computers' screens.</para>
- </simplesect>
- </preface>
- <part xml:id="users-guide">
- <title>User's Guide</title>
- <xi:include href="chapters/architecture.xml"/>
- <xi:include href="chapters/installing.xml"/>
- <xi:include href="chapters/docker.xml"/>
- <xi:include href="chapters/reverse-proxy.xml"/>
- <xi:include href="chapters/configuring.xml"/>
- <xi:include href="chapters/jdbc-auth.xml"/>
- <xi:include href="chapters/ldap-auth.xml"/>
- <xi:include href="chapters/duo-auth.xml"/>
- <xi:include href="chapters/totp-auth.xml"/>
- <xi:include href="chapters/header-auth.xml"/>
- <xi:include href="chapters/cas-auth.xml"/>
- <xi:include href="chapters/openid-auth.xml"/>
- <xi:include href="chapters/saml-auth.xml"/>
- <xi:include href="chapters/radius-auth.xml"/>
- <xi:include href="chapters/adhoc-connections.xml"/>
- <xi:include href="chapters/using.xml"/>
- <xi:include href="chapters/administration.xml"/>
- <xi:include href="chapters/troubleshooting.xml"/>
- </part>
- <part xml:id="developers-guide">
- <title>Developer's Guide</title>
- <xi:include href="chapters/protocol.xml"/>
- <xi:include href="chapters/libguac.xml"/>
- <xi:include href="chapters/guacamole-common.xml"/>
- <xi:include href="chapters/guacamole-common-js.xml"/>
- <xi:include href="chapters/guacamole-ext.xml"/>
- <xi:include href="chapters/adding-protocol.xml"/>
- <xi:include href="chapters/custom-auth.xml"/>
- <xi:include href="chapters/event-listeners.xml"/>
- <xi:include href="chapters/yourown.xml"/>
- </part>
- <part xml:id="appendices">
- <title>Appendices</title>
- <xi:include href="appendices/faq.xml"/>
- <xi:include href="references/protocol.xml"/>
- <index xml:id="book-index"/>
- </part>
-</book>
diff --git a/src/header-auth.md b/src/header-auth.md
new file mode 100644
index 0000000..5f21b9a
--- /dev/null
+++ b/src/header-auth.md
@@ -0,0 +1,78 @@
+HTTP header authentication
+==========================
+
+Guacamole supports delegating authentication to an arbitrary external service,
+relying on the presence of an HTTP header which contains the username of the
+authenticated user. This authentication method must be layered on top of some
+other authentication extension, such as those available from the main project
+website, in order to provide access to actual connections.
+
+:::{important}
+All external requests must be properly sanitized if this extension is used. The
+chosen HTTP header must be stripped from untrusted requests, such that the
+authentication service is the only possible source of that header. *If such
+sanitization is not performed, it will be trivial for malicious users to add
+this header manually, and thus gain unrestricted access.*
+:::
+
+(header-downloading)=
+
+Downloading the HTTP header authentication extension
+----------------------------------------------------
+
+The HTTP header authentication extension is available separately from the main
+`guacamole.war`. The link for this and all other officially-supported and
+compatible extensions for a particular version of Guacamole are provided on the
+release notes for that version. You can find the release notes for current
+versions of Guacamole here: <http://guacamole.apache.org/releases/>.
+
+The HTTP header authentication extension is packaged as a `.tar.gz` file
+containing only the extension itself, `guacamole-auth-header-1.2.0.jar`, which
+must ultimately be placed in `GUACAMOLE_HOME/extensions`.
+
+(installing-header-auth)=
+
+Installing HTTP header authentication
+-------------------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located within
+the `GUACAMOLE_HOME/extensions` directory. *If you are unsure where
+`GUACAMOLE_HOME` is located on your system, please consult
+[](configuring-guacamole) before proceeding.*
+
+To install the HTTP header authentication extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+ exist.
+
+2. Copy `guacamole-auth-header-1.2.0.jar` within `GUACAMOLE_HOME/extensions`.
+
+3. Configure Guacamole to use HTTP header authentication, as described below.
+
+(guac-header-config)=
+
+### Configuring Guacamole for HTTP header authentication
+
+The HTTP header authentication extension provides only one configuration
+property, and it is optional. By default, the extension will pull the username
+of the authenticated user from the `REMOTE_USER` header, if present. If your
+authentication system uses a different HTTP header, you will need to override
+this by specifying the `http-auth-header` property within
+[`guacamole.properties`](initial-setup):
+
+`http-auth-header`
+: The HTTP header containing the username of the authenticated user. This
+ property is optional. If not specified, `REMOTE_USER` will be used by
+ default.
+
+(completing-header-install)=
+
+### Completing the installation
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before HTTP header authentication can be used. *Doing this will disconnect all
+active users, so be sure that it is safe to do so prior to attempting
+installation.* When ready, restart your servlet container and give the new
+authentication a try.
+
diff --git a/src/chapters/images/duo-add-guacamole.png b/src/images/duo-add-guacamole.png
similarity index 100%
rename from src/chapters/images/duo-add-guacamole.png
rename to src/images/duo-add-guacamole.png
Binary files differ
diff --git a/src/chapters/images/duo-auth-factor-1.png b/src/images/duo-auth-factor-1.png
similarity index 100%
rename from src/chapters/images/duo-auth-factor-1.png
rename to src/images/duo-auth-factor-1.png
Binary files differ
diff --git a/src/chapters/images/duo-auth-factor-2.png b/src/images/duo-auth-factor-2.png
similarity index 100%
rename from src/chapters/images/duo-auth-factor-2.png
rename to src/images/duo-auth-factor-2.png
Binary files differ
diff --git a/src/chapters/images/duo-copy-details.png b/src/images/duo-copy-details.png
similarity index 100%
rename from src/chapters/images/duo-copy-details.png
rename to src/images/duo-copy-details.png
Binary files differ
diff --git a/src/chapters/images/duo-rename-guacamole.png b/src/images/duo-rename-guacamole.png
similarity index 100%
rename from src/chapters/images/duo-rename-guacamole.png
rename to src/images/duo-rename-guacamole.png
Binary files differ
diff --git a/src/chapters/images/edit-connection.png b/src/images/edit-connection.png
similarity index 100%
rename from src/chapters/images/edit-connection.png
rename to src/images/edit-connection.png
Binary files differ
diff --git a/src/chapters/images/edit-group-memberships.png b/src/images/edit-group-memberships.png
similarity index 100%
rename from src/chapters/images/edit-group-memberships.png
rename to src/images/edit-group-memberships.png
Binary files differ
diff --git a/src/chapters/images/edit-group.png b/src/images/edit-group.png
similarity index 100%
rename from src/chapters/images/edit-group.png
rename to src/images/edit-group.png
Binary files differ
diff --git a/src/chapters/images/edit-sharing-profile.png b/src/images/edit-sharing-profile.png
similarity index 100%
rename from src/chapters/images/edit-sharing-profile.png
rename to src/images/edit-sharing-profile.png
Binary files differ
diff --git a/src/chapters/images/edit-user-group.png b/src/images/edit-user-group.png
similarity index 100%
rename from src/chapters/images/edit-user-group.png
rename to src/images/edit-user-group.png
Binary files differ
diff --git a/src/chapters/images/edit-user-membership.png b/src/images/edit-user-membership.png
similarity index 100%
rename from src/chapters/images/edit-user-membership.png
rename to src/images/edit-user-membership.png
Binary files differ
diff --git a/src/chapters/images/edit-user.png b/src/images/edit-user.png
similarity index 100%
rename from src/chapters/images/edit-user.png
rename to src/images/edit-user.png
Binary files differ
diff --git a/src/chapters/images/file-browser.png b/src/images/file-browser.png
similarity index 100%
rename from src/chapters/images/file-browser.png
rename to src/images/file-browser.png
Binary files differ
diff --git a/src/chapters/images/file-transfers.png b/src/images/file-transfers.png
similarity index 100%
rename from src/chapters/images/file-transfers.png
rename to src/images/file-transfers.png
Binary files differ
diff --git a/src/chapters/images/guac-arch.png b/src/images/guac-arch.png
similarity index 100%
rename from src/chapters/images/guac-arch.png
rename to src/images/guac-arch.png
Binary files differ
diff --git a/src/chapters/images/guac-menu-disconnect.png b/src/images/guac-menu-disconnect.png
similarity index 100%
rename from src/chapters/images/guac-menu-disconnect.png
rename to src/images/guac-menu-disconnect.png
Binary files differ
diff --git a/src/chapters/images/guac-menu-share-link.png b/src/images/guac-menu-share-link.png
similarity index 100%
rename from src/chapters/images/guac-menu-share-link.png
rename to src/images/guac-menu-share-link.png
Binary files differ
diff --git a/src/chapters/images/guac-menu-share.png b/src/images/guac-menu-share.png
similarity index 100%
rename from src/chapters/images/guac-menu-share.png
rename to src/images/guac-menu-share.png
Binary files differ
diff --git a/src/chapters/images/guacamole-client-interface.png b/src/images/guacamole-client-interface.png
similarity index 100%
rename from src/chapters/images/guacamole-client-interface.png
rename to src/images/guacamole-client-interface.png
Binary files differ
diff --git a/src/chapters/images/guacamole-drive-download.png b/src/images/guacamole-drive-download.png
similarity index 100%
rename from src/chapters/images/guacamole-drive-download.png
rename to src/images/guacamole-drive-download.png
Binary files differ
diff --git a/src/chapters/images/guacamole-drive.png b/src/images/guacamole-drive.png
similarity index 100%
rename from src/chapters/images/guacamole-drive.png
rename to src/images/guacamole-drive.png
Binary files differ
diff --git a/src/chapters/images/guacamole-home-screen.png b/src/images/guacamole-home-screen.png
similarity index 100%
rename from src/chapters/images/guacamole-home-screen.png
rename to src/images/guacamole-home-screen.png
Binary files differ
diff --git a/src/chapters/images/guacamole-preferences.png b/src/images/guacamole-preferences.png
similarity index 100%
rename from src/chapters/images/guacamole-preferences.png
rename to src/images/guacamole-preferences.png
Binary files differ
diff --git a/src/chapters/images/guacamole-settings-sections.png b/src/images/guacamole-settings-sections.png
similarity index 100%
rename from src/chapters/images/guacamole-settings-sections.png
rename to src/images/guacamole-settings-sections.png
Binary files differ
diff --git a/src/chapters/images/manage-button.png b/src/images/manage-button.png
similarity index 100%
rename from src/chapters/images/manage-button.png
rename to src/images/manage-button.png
Binary files differ
diff --git a/src/chapters/images/manage-connections.png b/src/images/manage-connections.png
similarity index 100%
rename from src/chapters/images/manage-connections.png
rename to src/images/manage-connections.png
Binary files differ
diff --git a/src/chapters/images/manage-groups.png b/src/images/manage-groups.png
similarity index 100%
rename from src/chapters/images/manage-groups.png
rename to src/images/manage-groups.png
Binary files differ
diff --git a/src/chapters/images/manage-history.png b/src/images/manage-history.png
similarity index 100%
rename from src/chapters/images/manage-history.png
rename to src/images/manage-history.png
Binary files differ
diff --git a/src/chapters/images/manage-sessions.png b/src/images/manage-sessions.png
similarity index 100%
rename from src/chapters/images/manage-sessions.png
rename to src/images/manage-sessions.png
Binary files differ
diff --git a/src/chapters/images/manage-users.png b/src/images/manage-users.png
similarity index 100%
rename from src/chapters/images/manage-users.png
rename to src/images/manage-users.png
Binary files differ
diff --git a/src/chapters/images/session-filter-example-1.png b/src/images/session-filter-example-1.png
similarity index 100%
rename from src/chapters/images/session-filter-example-1.png
rename to src/images/session-filter-example-1.png
Binary files differ
diff --git a/src/chapters/images/session-filter-example-2.png b/src/images/session-filter-example-2.png
similarity index 100%
rename from src/chapters/images/session-filter-example-2.png
rename to src/images/session-filter-example-2.png
Binary files differ
diff --git a/src/chapters/images/totp-auth-factor-1.png b/src/images/totp-auth-factor-1.png
similarity index 100%
rename from src/chapters/images/totp-auth-factor-1.png
rename to src/images/totp-auth-factor-1.png
Binary files differ
diff --git a/src/chapters/images/totp-auth-factor-2.png b/src/images/totp-auth-factor-2.png
similarity index 100%
rename from src/chapters/images/totp-auth-factor-2.png
rename to src/images/totp-auth-factor-2.png
Binary files differ
diff --git a/src/chapters/images/totp-enroll-detail.png b/src/images/totp-enroll-detail.png
similarity index 100%
rename from src/chapters/images/totp-enroll-detail.png
rename to src/images/totp-enroll-detail.png
Binary files differ
diff --git a/src/chapters/images/totp-enroll.png b/src/images/totp-enroll.png
similarity index 100%
rename from src/chapters/images/totp-enroll.png
rename to src/images/totp-enroll.png
Binary files differ
diff --git a/src/chapters/images/touchpad.png b/src/images/touchpad.png
similarity index 100%
rename from src/chapters/images/touchpad.png
rename to src/images/touchpad.png
Binary files differ
diff --git a/src/chapters/images/touchscreen.png b/src/images/touchscreen.png
similarity index 100%
rename from src/chapters/images/touchscreen.png
rename to src/images/touchscreen.png
Binary files differ
diff --git a/src/index.md b/src/index.md
new file mode 100644
index 0000000..4f5126f
--- /dev/null
+++ b/src/index.md
@@ -0,0 +1,78 @@
+Apache Guacamole Manual
+=======================
+
+:::{note}
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the [NOTICE] file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at:
+
+<http://www.apache.org/licenses/LICENSE-2.0>
+
+Unless required by applicable law or agreed to in writing, software distributed
+under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+
+[NOTICE]: https://raw.githubusercontent.com/apache/guacamole-manual/master/NOTICE
+:::
+
+:::{toctree}
+:caption: Overview
+:name: overview
+:maxdepth: 1
+
+introduction
+:::
+
+:::{toctree}
+:caption: User's Guide
+:name: users-guide
+:maxdepth: 1
+
+guacamole-architecture
+installing-guacamole
+guacamole-docker
+reverse-proxy
+configuring-guacamole
+jdbc-auth
+ldap-auth
+duo-auth
+totp-auth
+header-auth
+cas-auth
+openid-auth
+saml-auth
+radius-auth
+adhoc-connections
+using-guacamole
+administration
+troubleshooting
+:::
+
+:::{toctree}
+:caption: Developer's Guide
+:name: developers-guide
+:maxdepth: 1
+
+guacamole-protocol
+libguac
+guacamole-common
+guacamole-common-js
+guacamole-ext
+custom-protocols
+custom-auth
+event-listeners
+writing-you-own-guacamole-app
+:::
+
+:::{toctree}
+:caption: Appendices
+:name: appendices
+:maxdepth: 1
+
+protocol-reference
+:::
+
diff --git a/src/installing-guacamole.md b/src/installing-guacamole.md
new file mode 100644
index 0000000..32c9562
--- /dev/null
+++ b/src/installing-guacamole.md
@@ -0,0 +1,740 @@
+Installing Guacamole natively
+=============================
+
+Guacamole is separated into two pieces: guacamole-server, which provides the
+guacd proxy and related libraries, and guacamole-client, which provides the
+client to be served by your servlet container, usually [Apache
+Tomcat](http://tomcat.apache.org/).
+
+guacamole-client is available in binary form, but guacamole-server must be
+built from source. Don't be discouraged: building the components of Guacamole
+from source is *not* as difficult as it sounds, and the build process is
+automated. You just need to be sure you have the necessary tools installed
+ahead of time. With the necessary dependencies in place, building Guacamole
+only takes a few minutes.
+
+(building-guacamole-server)=
+
+Building guacamole-server
+-------------------------
+
+guacamole-server contains all the native, server-side components required by
+Guacamole to connect to remote desktops. It provides a common C library,
+libguac, which all other native components depend on, as well as separate
+libraries for each supported protocol, and guacd, the heart of Guacamole.
+
+guacd is the proxy daemon that runs on your Guacamole server, accepts users'
+connections that are tunneled through the Guacamole web application, and then
+connects to remote desktops on their behalf. Building guacd creates an
+executable called {program}`guacd` which can be run manually or, if you wish,
+automatically when your computer starts up.
+
+To build guacamole-server, you will need a C compiler (such as gcc) and the
+libraries that guacamole-server depends on. Some dependencies are absolutely
+required, while others are optional. The presence of optional dependencies
+enables additional features.
+
+:::{important}
+Many Linux distributions separate library packages into binary and
+"development" packages; *you will need to install the development packages*.
+These will usually end in a "-dev" or "-devel" suffix.
+:::
+
+### Required dependencies
+
+In order to build guacamole-server, you will need Cairo, libjpeg (or
+libjpeg-turbo), libpng, and libuuid (or the OSSP UUID library). These libraries
+are strictly required *in all cases* - Guacamole cannot be built without them.
+
+[Cairo](http://cairographics.org/)
+: Cairo is used by libguac for graphics rendering. Guacamole cannot function
+ without Cairo installed.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libcairo2-dev`
+ * - Fedora / CentOS / RHEL package
+ - `cairo-devel`
+ :::
+
+[libjpeg-turbo](http://libjpeg-turbo.virtualgl.org/)
+: libjpeg-turbo is used by libguac to provide JPEG support. Guacamole will not
+ build without this library present:
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian package
+ - `libjpeg62-turbo-dev`
+ * - Ubuntu package
+ - `libjpeg-turbo8-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libjpeg-turbo-devel`
+ :::
+
+ If libjpeg-turbo is unavailable on your platform, and you do not wish to
+ build it from source, [libjpeg](http://www.ijg.org/) will work as well,
+ though it will not be quite as fast:
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libjpeg62-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libjpeg-devel`
+ :::
+
+[libpng](http://www.libpng.org/pub/png/libpng.html)
+: libpng is used by libguac to write PNG images, the core image type used by
+ the Guacamole protocol. Guacamole cannot function without libpng.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libpng12-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libpng-devel`
+ :::
+
+[libtool](https://www.gnu.org/software/libtool/manual/libtool.html)
+: libtool is used during the build process. libtool creates compiled libraries
+ needed for Guacamole.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libtool-bin`
+ * - Fedora / CentOS / RHEL package
+ - `libtool`
+ :::
+
+libuuid (part of [util-linux](https://www.kernel.org/pub/linux/utils/util-linux/))
+: libuuid is used by libguac to assign unique, internal IDs to each Guacamole
+ user and connection. These unique IDs are the basis for connection sharing
+ support.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `uuid-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libuuid-devel`
+ :::
+
+ If libuuid is unavailable, the [OSSP UUID](http://www.ossp.org/pkg/lib/uuid/)
+ library may also be used:
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libossp-uuid-dev`
+ * - Fedora / CentOS / RHEL package
+ - `uuid-devel`
+ :::
+
+### Optional dependencies
+
+The optional dependencies of Guacamole dictate which parts of guacamole-server
+will be built. This includes the support for various remote desktop protocols,
+as well as any additional features of those protocols:
+
+* VNC support depends on the libvncclient library, which is part of
+ libVNCServer.
+
+* RDP support depends on a recent version of FreeRDP (2.0.0 or higher, but
+ please *not a non-release version from git*).
+
+* SSH support depends on libssh2, OpenSSL and Pango (a font rendering and text
+ layout library, used by Guacamole's built-in terminal emulator).
+
+* Telnet depends on libtelnet and Pango.
+
+* Kubernetes support depends on libwebsockets, OpenSSL, and Pango.
+
+The `guacenc` utility, provided by guacamole-server to translate screen
+recordings into video, depends on FFmpeg, and will only be built if at least
+the libavcodec, libavformat, libavutil, and libswscale libraries provided by
+FFmpeg are installed.
+
+:::{important}
+If you lack these dependencies, *then the features or protocols which
+depend on them will not be enabled*. Please read this section
+carefully before deciding not to install an optional dependency.
+:::
+
+[FFmpeg](https://ffmpeg.org/)
+: The libavcodec, libavformat, libavutil, and libswscale libraries provided by
+ FFmpeg are used by `guacenc` to encode video streams when translating
+ recordings of Guacamole sessions. Without FFmpeg, the `guacenc` utility will
+ simply not be built.
+
+ If you do not wish to make graphical recordings of Guacamole sessions, or do
+ not wish to translate such recordings into video, then FFmpeg is not needed.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libavcodec-dev`, `libavformat-dev`, `libavutil-dev`, `libswsccale-dev`
+ * - Fedora / CentOS / RHEL package
+ - `ffmpeg-devel`
+ :::
+
+[FreeRDP](http://www.freerdp.com/)
+: FreeRDP 2.0.0 or later is required for RDP support. If you do not wish to
+ build RDP support, this library is not needed.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `freerdp2-dev`
+ * - Fedora / CentOS / RHEL package
+ - `freerdp-devel`
+ :::
+
+[Pango](http://www.pango.org/)
+: Pango is a text layout library which Guacamole uses to render text for
+ protocols that require a terminal (Kubernetes, SSH, and telnet). If you do
+ not wish to build any terminal-based protocol support, this library is not
+ needed.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libpango1.0-dev`
+ * - Fedora / CentOS / RHEL package
+ - `pango-devel`
+ :::
+
+[libssh2](http://www.libssh2.org/)
+: libssh2 is required for SSH and SFTP support. If you do not wish to build SSH
+ or SFTP support, this library is not needed.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libssh2-1-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libssh2-devel`
+ :::
+
+[libtelnet](https://github.com/seanmiddleditch/libtelnet)
+: libtelnet is required for telnet support. If you do not wish to build telnet
+ support, this library is not needed.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libtelnet-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libtelnet-devel`
+ :::
+
+[libVNCServer](http://libvnc.github.io/)
+: libVNCServer provides libvncclient, which is required for VNC support. If you
+ do not wish to build VNC support, this library is not needed.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libvncserver-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libvncserver-devel`
+ :::
+
+[libwebsockets](https://libwebsockets.org/)
+: libwebsockets is required for Kubernetes support. If you do not wish to build
+ Kubernetes support, this library is not needed.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libwebsockets-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libwebsockets-devel`
+ :::
+
+[PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/)
+: PulseAudio provides libpulse, which is used by Guacamole's VNC support to
+ provide experimental audio support. If you are not going to be using the
+ experimental audio support for VNC, you do not need this library.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libpulse-dev`
+ * - Fedora / CentOS / RHEL package
+ - `pulseaudio-libs-devel`
+ :::
+
+[OpenSSL](https://www.openssl.org/)
+: OpenSSL provides support for SSL and TLS - two common encryption schemes that
+ make up the majority of encrypted web traffic.
+
+ If you have libssl installed, guacd will be built with SSL support, allowing
+ communication between the web application and guacd to be encrypted. This
+ library is also required for SSH support, for manipulating public/private keys,
+ and for Kubernetes support, for SSL/TLS connections to the Kubernetes server.
+
+ Without SSL support, there will be no option to encrypt communication to
+ guacd, and support for SSH and Kubernetes cannot be built.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libssl-dev`
+ * - Fedora / CentOS / RHEL package
+ - `openssl-devel`
+ :::
+
+[libvorbis](http://xiph.org/vorbis/)
+: libvorbis provides support for Ogg Vorbis - a free and open standard for
+ sound compression. If installed, libguac will be built with support for Ogg
+ Vorbis, and protocols supporting audio will use Ogg Vorbis compression when
+ possible.
+
+ Otherwise, sound will only be encoded as WAV (uncompressed), and will only be
+ available if your browser also supports WAV.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libvorbis-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libvorbis-devel`
+ :::
+
+[libwebp](https://developers.google.com/speed/webp/)
+: libwebp is used by libguac to write WebP images. Though support for WebP is
+ not mandated by the Guacamole protocol, WebP images will be used if supported
+ by both the browser and by libguac.
+
+ Lacking WebP support, Guacamole will simply use JPEG in cases that it would
+ have preferred WebP.
+
+ :::{list-table}
+ :stub-columns: 1
+ * - Debian / Ubuntu package
+ - `libwebp-dev`
+ * - Fedora / CentOS / RHEL package
+ - `libwebp-devel`
+ :::
+
+(guacamole-server-source)=
+
+### Obtaining the source code
+
+You can obtain a copy of the guacamole-server source from the Guacamole project
+web site. These releases are stable snapshots of the latest code which have
+undergone enough testing that the Guacamole team considers them fit for public
+consumption. Source downloaded from the project web site will take the form of
+a `.tar.gz` archive which you can extract
+from the command line:
+
+```console
+$ tar -xzf guacamole-server-1.3.0.tar.gz
+$ cd guacamole-server-1.3.0/
+$
+```
+
+If you want the absolute latest code, and don't care that the code hasn't been
+as rigorously tested as the code in stable releases, you can also clone the
+Guacamole team's git repository on GitHub:
+
+```console
+$ git clone git://github.com/apache/guacamole-server.git
+Cloning into 'guacamole-server'...
+remote: Counting objects: 6769, done.
+remote: Compressing objects: 100% (2244/2244), done.
+remote: Total 6769 (delta 3058), reused 6718 (delta 3008)
+Receiving objects: 100% (6769/6769), 2.32 MiB | 777 KiB/s, done.
+Resolving deltas: 100% (3058/3058), done.
+$
+```
+
+(guacamole-server-build-process)=
+
+### The build process
+
+Once the guacamole-server source has been downloaded and extracted, you need to
+run `configure`. This is a shell script automatically generated by GNU
+Autotools, a popular build system used by the Guacamole project for
+guacamole-server. Running `configure` will determine which libraries are
+available on your system and will select the appropriate components for
+building depending on what you actually have installed.
+
+:::{important}
+Source downloaded directly from git will not contain this `configure` script,
+as autogenerated code is not included in the project's repositories. If you
+downloaded the code from the project's git repositories directly, you will need
+to generate `configure` manually:
+
+```console
+$ cd guacamole-server/
+$ autoreconf -fi
+$
+```
+
+Doing this requires GNU Autotools to be installed.
+
+Source archives downloaded from the project website contain the `configure`
+script and all other necessary build files, and thus do not require GNU
+Autotools to be installed on the build machine.
+:::
+
+Once you run `configure`, you can see what a listing of what libraries were
+found and what it has determined should be built:
+
+```console
+$ ./configure --with-init-dir=/etc/init.d
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+...
+
+------------------------------------------------
+guacamole-server version 1.3.0
+------------------------------------------------
+
+ Library status:
+
+ freerdp2 ............ yes
+ pango ............... yes
+ libavcodec .......... yes
+ libavformat ......... yes
+ libavutil ........... yes
+ libssh2 ............. yes
+ libssl .............. yes
+ libswscale .......... yes
+ libtelnet ........... yes
+ libVNCServer ........ yes
+ libvorbis ........... yes
+ libpulse ............ yes
+ libwebsockets ....... yes
+ libwebp ............. yes
+ wsock32 ............. no
+
+ Protocol support:
+
+ Kubernetes .... yes
+ RDP ........... yes
+ SSH ........... yes
+ Telnet ........ yes
+ VNC ........... yes
+
+ Services / tools:
+
+ guacd ...... yes
+ guacenc .... yes
+ guaclog .... yes
+
+ Init scripts: /etc/init.d
+ Systemd units: no
+
+Type "make" to compile guacamole-server.
+
+$
+```
+
+The `--with-init-dir=/etc/init.d` shown above prepares the build to install a
+startup script for guacd into the `/etc/init.d` directory, such that we can
+later easily configure guacd to start automatically on boot. If you do not wish
+guacd to start automatically at boot, leave off the `--with-init-dir` option.
+If the directory containing your distribution's startup scripts differs from
+the common `/etc/init.d`, replace `/etc/init.d` with the proper directory here.
+You may need to consult your distribution's documentation, or do a little
+digging in `/etc`, to determine the proper location.
+
+Here, `configure` has found everything, including all optional libraries, and
+will build all protocol support, even support for Ogg Vorbis sound in RDP. If
+you are missing some libraries, some of the "`yes`" answers above will read
+"`no`". If a library which is strictly required is missing, the script will
+fail outright, and you will need to install the missing dependency. If, after
+running `configure`, you find support for something you wanted is missing,
+simply install the corresponding dependencies and run `configure` again.
+
+:::{important}
+All protocols that require a terminal (Kubernetes, SSH, and telnet) require
+that fonts are installed on the Guacamole server in order to function, as
+output from the terminal cannot be rendered otherwise. Support for these
+protocols will build just fine if fonts are not installed, but it will fail to
+connect when used:
+
+```
+Aug 23 14:09:45 my-server guacd[5606]: Unable to get font "monospace"
+```
+
+If terminal-based connections are not working and you see such a message in
+syslog, you should make sure fonts are installed and try again.
+:::
+
+Once `configure` is finished, just type "`make`", and it will guacamole-server
+will compile:
+
+```console
+$ make
+Making all in src/libguac
+make[1]: Entering directory `/home/mjumper/guacamole/guacamole-server/src/libguac'
+...
+make[1]: Leaving directory `/home/mjumper/guacamole/guacamole-server/src/protocols/vnc'
+make[1]: Entering directory `/home/mjumper/guacamole/guacamole-server'
+make[1]: Nothing to be done for `all-am'.
+make[1]: Leaving directory `/home/mjumper/guacamole/guacamole-server'
+$
+```
+
+Quite a bit of output will scroll up the screen as all the components are
+compiled.
+
+(guacamole-server-installation)=
+
+### Installation
+
+Once everything finishes, all you have left to do is type "`make install`" to
+install the components that were built, and then "`ldconfig`" to update your
+system's cache of installed libraries:
+
+```console
+# make install
+Making install in src/libguac
+make[1]: Entering directory `/home/mjumper/guacamole/guacamole-server/src/libguac'
+make[2]: Entering directory `/home/mjumper/guacamole/guacamole-server/src/libguac'
+...
+----------------------------------------------------------------------
+Libraries have been installed in:
+ /usr/local/lib
+
+If you ever happen to want to link against installed libraries
+in a given directory, LIBDIR, you must either use libtool, and
+specify the full pathname of the library, or use the `-LLIBDIR'
+flag during linking and do at least one of the following:
+ - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
+ during execution
+ - add LIBDIR to the `LD_RUN_PATH' environment variable
+ during linking
+ - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
+ - have your system administrator add LIBDIR to `/etc/ld.so.conf'
+
+See any operating system documentation about shared libraries for
+more information, such as the ld(1) and ld.so(8) manual pages.
+----------------------------------------------------------------------
+make[2]: Nothing to be done for `install-data-am'.
+make[2]: Leaving directory `/home/mjumper/guacamole/guacamole-server/src/protocols/vnc'
+make[1]: Leaving directory `/home/mjumper/guacamole/guacamole-server/src/protocols/vnc'
+make[1]: Entering directory `/home/mjumper/guacamole/guacamole-server'
+make[2]: Entering directory `/home/mjumper/guacamole/guacamole-server'
+make[2]: Nothing to be done for `install-exec-am'.
+make[2]: Nothing to be done for `install-data-am'.
+make[2]: Leaving directory `/home/mjumper/guacamole/guacamole-server'
+make[1]: Leaving directory `/home/mjumper/guacamole/guacamole-server'
+# ldconfig
+#
+```
+
+At this point, everything is installed, but guacd is not running. You will need
+to run guacd in order to use Guacamole once the client components are installed
+as well.
+
+Beware that even after installing guacd and its startup script, you will likely
+still have to activate the service for it to start automatically. Doing this
+varies by distribution, but each distribution will have documentation
+describing how to do so.
+
+(building-guacamole-client)=
+
+guacamole-client
+----------------
+
+:::{important}
+Normally, you don't need to build guacamole-client, as it is written in Java
+and is cross-platform. You can easily obtain the latest version of
+guacamole-client from the release archives of the Guacamole project web site,
+including all supported extensions, without having to build it yourself.
+
+If you do not want to build guacamole-client from source, just download
+`guacamole.war` from the project web site, along with any desired extensions,
+and skip ahead to [](deploying-guacamole).
+:::
+
+guacamole-client contains all Java and JavaScript components of Guacamole
+(guacamole, guacamole-common, guacamole-ext, and guacamole-common-js). These
+components ultimately make up the web application that will serve the HTML5
+Guacamole client to users that connect to your server. This web application
+will then connect to guacd, part of guacamole-server, on behalf of connected
+users in order to serve them any remote desktop they are authorized to access.
+
+To compile guacamole-client, all you need is Apache Maven and a copy of the
+Java JDK. Most, if not all, Linux distributions will provide packages for
+these.
+
+You can obtain a copy of the guacamole-client source from the Guacamole project
+web site. These releases are stable snapshots of the latest code which have
+undergone enough testing that the Guacamole team considers them fit for public
+consumption. Source downloaded from the project web site will take the form of
+a `.tar.gz` archive which you can extract from the command line:
+
+```console
+$ tar -xzf guacamole-client-1.3.0.tar.gz
+$ cd guacamole-client-1.3.0/
+$
+```
+
+As with guacamole-server, if you want the absolute latest code, and don't care
+that the code hasn't been as rigorously tested as the code in stable releases,
+you can also clone the Guacamole team's git repository on GitHub:
+
+```console
+$ git clone git://github.com/apache/guacamole-client.git
+Cloning into 'guacamole-client'...
+remote: Counting objects: 12788, done.
+remote: Compressing objects: 100% (4183/4183), done.
+remote: Total 12788 (delta 3942), reused 12667 (delta 3822)
+Receiving objects: 100% (12788/12788), 3.23 MiB | 799 KiB/s, done.
+Resolving deltas: 100% (3942/3942), done.
+$
+```
+
+Unlike guacamole-server, even if you grab the code from the git repositories,
+you won't need to run anything before building. There are no scripts that need
+to be generated before building - all Maven needs is the `pom.xml` file
+provided with the source.
+
+To build guacamole-client, just run "`mvn package`". This will invoke Maven
+to automatically build and package all components, producing a single `.war`
+file, which contains the entire web application:
+
+```console
+$ mvn package
+[INFO] Scanning for projects...
+[INFO] ------------------------------------------------------------------------
+[INFO] Reactor Build Order:
+[INFO]
+[INFO] guacamole-common
+[INFO] guacamole-ext
+[INFO] guacamole-common-js
+[INFO] guacamole
+[INFO] guacamole-auth-cas
+[INFO] guacamole-auth-duo
+[INFO] guacamole-auth-header
+[INFO] guacamole-auth-jdbc
+[INFO] guacamole-auth-jdbc-base
+[INFO] guacamole-auth-jdbc-mysql
+[INFO] guacamole-auth-jdbc-postgresql
+[INFO] guacamole-auth-jdbc-sqlserver
+[INFO] guacamole-auth-jdbc-dist
+[INFO] guacamole-auth-ldap
+[INFO] guacamole-auth-openid
+[INFO] guacamole-auth-quickconnect
+[INFO] guacamole-auth-totp
+[INFO] guacamole-example
+[INFO] guacamole-playback-example
+[INFO] guacamole-client
+...
+[INFO] ------------------------------------------------------------------------
+[INFO] Reactor Summary:
+[INFO]
+[INFO] guacamole-common ................................... SUCCESS [ 21.852 s]
+[INFO] guacamole-ext ...................................... SUCCESS [ 9.055 s]
+[INFO] guacamole-common-js ................................ SUCCESS [ 1.988 s]
+[INFO] guacamole .......................................... SUCCESS [ 18.040 s]
+[INFO] guacamole-auth-cas ................................. SUCCESS [ 4.203 s]
+[INFO] guacamole-auth-duo ................................. SUCCESS [ 2.251 s]
+[INFO] guacamole-auth-header .............................. SUCCESS [ 1.399 s]
+[INFO] guacamole-auth-jdbc ................................ SUCCESS [ 1.396 s]
+[INFO] guacamole-auth-jdbc-base ........................... SUCCESS [ 3.266 s]
+[INFO] guacamole-auth-jdbc-mysql .......................... SUCCESS [ 4.665 s]
+[INFO] guacamole-auth-jdbc-postgresql ..................... SUCCESS [ 3.764 s]
+[INFO] guacamole-auth-jdbc-sqlserver ...................... SUCCESS [ 3.738 s]
+[INFO] guacamole-auth-jdbc-dist ........................... SUCCESS [ 1.214 s]
+[INFO] guacamole-auth-ldap ................................ SUCCESS [ 1.991 s]
+[INFO] guacamole-auth-openid .............................. SUCCESS [ 2.204 s]
+[INFO] guacamole-auth-quickconnect ........................ SUCCESS [ 2.983 s]
+[INFO] guacamole-auth-totp ................................ SUCCESS [ 8.154 s]
+[INFO] guacamole-example .................................. SUCCESS [ 0.895 s]
+[INFO] guacamole-playback-example ......................... SUCCESS [ 0.795 s]
+[INFO] guacamole-client ................................... SUCCESS [ 7.478 s]
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD SUCCESS
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 01:41 min
+[INFO] Finished at: 2018-10-15T17:08:29-07:00
+[INFO] Final Memory: 42M/379M
+[INFO] ------------------------------------------------------------------------
+$
+```
+
+Once the Guacamole web application is built, there will be a .war file in the
+`guacamole/target/` subdirectory of the current directory (the directory you
+were in when you ran mvn), ready to be deployed to a servlet container like
+Tomcat.
+
+(deploying-guacamole)=
+
+Deploying Guacamole
+-------------------
+
+The web application portion of Guacamole is packaged as a fully self-contained
+`.war` file. If you downloaded Guacamole from the main project web site, this
+file will be called `guacamole.war`. Deploying this involves copying the file
+into the directory your servlet container uses for `.war` files. In the case of
+Tomcat, this will be `CATALINA_HOME/webapps/`. The location of `CATALINA_HOME`
+will vary by how Tomcat was installed, but is commonly `/var/lib/tomcat`,
+`/var/lib/tomcat7`, or similar:
+
+```console
+# cp guacamole.war /var/lib/tomcat/webapps
+#
+```
+
+If you have built guacamole-client from source, the required `.war` file will
+be within the `guacamole/target/` directory and will contain an additional
+version suffix. As Tomcat will determine the location of the web application
+from the name of the `.war` file, you will likely want to rename this to simply
+`guacamole.war` while copying:
+
+```console
+# cp guacamole/target/guacamole-1.3.0.war /var/lib/tomcat/webapps/guacamole.war
+#
+```
+
+Again, if you are using a different servlet container or if Tomcat is installed
+to a different location, you will need to check the documentation of your
+servlet container, distribution, or both to determine the proper location for
+deploying `.war` files like `guacamole.war`.
+
+Once the `.war` file is in place, you may need to restart Tomcat to force
+Tomcat to deploy the new web application, and the guacd daemon must be started
+if it isn't running already. The command to restart Tomcat and guacd will vary
+by distribution. Typically, you can do this by running the corresponding init
+scripts with the "restart" option:
+
+```console
+# /etc/init.d/tomcat7 restart
+Stopping Tomcat... OK
+Starting Tomcat... OK
+# /etc/init.d/guacd start
+Starting guacd: SUCCESS
+guacd[6229]: INFO: Guacamole proxy daemon (guacd) version 1.3.0 started
+#
+```
+
+:::{important}
+If you want Guacamole to start on boot, you will need to configure
+the Tomcat and guacd services to run automatically. Your distribution
+will provide documentation for doing this.
+:::
+
+After restarting Tomcat and starting guacd, Guacamole is successfully
+installed, though it will not be fully running. In its current state, it is
+completely unconfigured, and further steps are required to add at least one
+Guacamole user and a few connections. This is covered in
+[](configuring-guacamole).
+
+### What about WebSocket?
+
+Guacamole will use WebSocket automatically if supported by the browser and your
+servlet container. In the event that Guacamole cannot connect using WebSocket,
+it will immediately and transparently fall back to using HTTP.
+
+WebSocket is supported in Guacamole for Tomcat 7.0.37 or higher, Jetty 8 or
+higher, and any servlet container supporting JSR 356, the standardized Java API
+for WebSocket.
+
diff --git a/src/introduction.md b/src/introduction.md
new file mode 100644
index 0000000..95f4913
--- /dev/null
+++ b/src/introduction.md
@@ -0,0 +1,161 @@
+Introduction
+============
+
+This book is the official Apache Guacamole manual, written by the upstream
+developers of the Guacamole project. It is also the official general
+documentation, with an online version available at
+<http://guacamole.apache.org/>. It is a work in progress which will be
+continuously updated as Guacamole changes with each release.
+
+We decided to maintain the documentation for Guacamole as a book, as there is
+an awful lot that can be done with the Guacamole web application, and even more
+that can be done with the API. This book is intended to explore the
+possibilities of Guacamole as an application, and to provide documentation
+necessary to install, maintain, and use Guacamole.
+
+For the sake of users and administrators, we have provided a high-level
+overview of Guacamole's architecture and technical design, as well as basic
+usage instructions and installation instructions for common platforms.
+
+For the sake of developers, we have provided a protocol reference and tutorials
+for common tasks (implementing protocol support, integrating Guacamole into
+your own application, etc.) to give a good starting point beyond simply looking
+at the Guacamole codebase.
+
+This particular edition of the Guacamole Manual covers Guacamole version
+{{ version }}. New releases which create new features or break compatibility
+will result in new editions of the user's guide, as will any necessary
+corrections. As the official documentation for the project, this book will
+always be freely available in its entirety online.
+
+(what-is-guac)=
+
+What is Guacamole?
+------------------
+
+Guacamole is an HTML5 web application that provides access to desktop
+environments using remote desktop protocols (such as VNC or RDP).
+Guacamole is also the project that produces this web application, and
+provides an API that drives it. This API can be used to power other
+similar applications or services.
+
+"Guacamole" is most commonly used to refer to the web application
+produced by the Guacamole project using their API. This web application
+is part of a stack that provides a protocol-agnostic remote desktop
+gateway. Written in JavaScript and using only HTML5 and other standards,
+the client part of Guacamole requires nothing more than a modern web
+browser or web-enabled device when accessing any of the desktops served.
+
+Historically, Guacamole was an HTML5 VNC client, and before that, a
+JavaScript Telnet client called RealMint ("RealMint" is an anagram for
+"terminal"), but this is no longer the case. Guacamole's architecture
+has grown to encompass remote desktop in general, and can be used as a
+gateway for any number of computers. Originally a proof-of-concept,
+Guacamole is now performant enough for daily use, and all Guacamole
+development is done over Guacamole.
+
+As an API, Guacamole provides a common and efficient means of streaming
+text data over a JavaScript-based tunnel using either HTTP or WebSocket,
+and a client implementation which supports the Guacamole protocol and
+renders the remote display when combined with a Guacamole protocol
+stream from the tunnel.
+
+It provides cross-browser mouse and keyboard events, an XML-driven
+on-screen keyboard, and synchronized nestable layers with
+hardware-accelerated compositing. Projects that wish to provide remote
+desktop support over HTML5 can leverage the years of research and
+development that went into Guacamole by incorporating the API into their
+application or service.
+
+(access-from-anywhere)=
+
+Why use Guacamole?
+------------------
+
+The principle reason to use Guacamole is constant, world-wide,
+unfettered access to your computers.
+
+Guacamole allows access one or more desktops from anywhere remotely,
+without having to install a client, particularly when installing a
+client is not possible. By setting up a Guacamole server, you can
+provide access to any other computer on the network from virtually any
+other computer on the internet, anywhere in the world. Even mobile
+phones or tablets can be used, without having to install anything.
+
+As a true web application whose communication is over HTTP or HTTPS
+only, Guacamole allows you to access your machines from anywhere without
+violating the policy of your workplace, and without requiring the
+installation of special clients. The presence of a proxy or corporate
+firewall does not prevent Guacamole use.
+
+(access-from-anything)=
+
+Access your computers from any device
+-------------------------------------
+
+As Guacamole requires only a reasonably-fast, standards-compliant
+browser, Guacamole will run on many devices, including mobile phones and
+tablets.
+
+Guacamole is specifically designed to not care whether you have a mouse,
+keyboard, touchscreen, or any combination of those.
+
+One of the major design philosophies behind Guacamole is that it should
+never assume you have a particular device (ie: a mobile phone) just
+because your browser has or is missing a specific feature (ie: touch
+events or a smallish screen). Guacamole's codebase provides support for
+both mouse and touch events simultaneously, without choosing one over
+the other, while the interface is intended to be usable regardless of
+screen size.
+
+Barring bugs, you should be able to use Guacamole on just about any
+modern device with a web browser.
+
+(non-physical-computer)=
+
+Keep a computer in the "cloud"
+------------------------------
+
+Ignoring the buzzword, it's often useful to have a computer that has no
+dedicated physical hardware, where its processing and storage power are
+handled transparently by redundant systems in some remote datacenter.
+
+Computers hosted on virtualized hardware are more resilient to failures,
+and with so many companies now offering on-demand computing resources,
+Guacamole is a perfect way to access several machines that are only
+accessible over the internet.
+
+In fact, all Guacamole development is done on computers like this. This
+is partly because we like the mobility, and partly because we want to
+ensure Guacamole is always performant enough for daily use.
+
+(group-access)=
+
+Provide easy access to a group
+------------------------------
+
+Guacamole allows you to centralize access to a large group of machines,
+and specify on a per-user basis which machines are accessible. Rather
+than remember a list of machines and credentials, users need only log
+into a central server and click on one of the connections listed.
+
+If you have multiple computers which you would like to access remotely,
+or you are part of a group where each person has a set of machines that
+they need remote access to, Guacamole is a good way to provide that
+access while also ensuring that access is available from anywhere.
+
+(adding-remote-access)=
+
+Adding HTML5 remote access to your existing infrastructure
+----------------------------------------------------------
+
+As Guacamole is an API, not just a web application, the core components
+and libraries provided by the Guacamole project can be used to add HTML5
+remote access features to an existing application. You need not use the
+main Guacamole web application; you can write (or integrate with) your
+own rather easily.
+
+If you host an on-demand computing service, adding HTML5-based remote
+access allows users of your service more broad access; users need
+nothing more than a web browser to see their computers' screens.
+
diff --git a/src/jdbc-auth.md b/src/jdbc-auth.md
new file mode 100644
index 0000000..221f067
--- /dev/null
+++ b/src/jdbc-auth.md
@@ -0,0 +1,1856 @@
+Database authentication
+=======================
+
+Guacamole supports authentication via MySQL, PostgreSQL, or SQL Server
+databases through extensions available from the project website. Using a
+database for authentication provides additional features, such as the ability
+to use load balancing groups of connections and a web-based administrative
+interface. Unlike the default, XML-driven authentication module, all changes to
+users and connections take effect immediately; users need not logout and back
+in to see new connections.
+
+While most authentication extensions function independently, the database
+authentication can act in a subordinate role, allowing users and user groups
+from other authentication extensions to be associated with connections within
+the database. Users and groups are considered identical to those within the
+database if they have the same names, and the authentication result of another
+extension will be trusted if it succeeds. A user with an account under multiple
+systems will thus be able to see data from each system after successfully
+logging in. For more information on using the database authentication alongside
+other mechanisms, see [](ldap-and-database) within [](ldap-auth).
+
+To use the database authentication extension, you will need:
+
+1. A supported database - currently MariaDB, MySQL, PostgreSQL, or SQL Server.
+
+2. Sufficient permission to create new databases, to create new users, and to
+ grant those users permissions.
+
+3. Network access to the database from the Guacamole server.
+
+:::{important}
+This chapter involves modifying the contents of `GUACAMOLE_HOME` - the
+Guacamole configuration directory. If you are unsure where `GUACAMOLE_HOME` is
+located on your system, please consult [](configuring-guacamole) before
+proceeding.
+:::
+
+Downloading the database authentication extension
+-------------------------------------------------
+
+The database authentication extension is available separately from the main
+`guacamole.war`. The link for this and all other officially-supported and
+compatible extensions for a particular version of Guacamole are provided on the
+release notes for that version. You can find the release notes for current
+versions of Guacamole here: <http://guacamole.apache.org/releases/>.
+
+The database authentication extension is packaged as a `.tar.gz` file
+containing several database-specific directories. Only one of the directories
+within the archive will be applicable to you, depending on whether you are
+using MariaDB, MySQL, PostgreSQL, or SQL Server.
+
+Each database-specific directory contains a `schema/` directory and `.jar` file
+(the actual Guacamole extension). The Guacamole extension `.jar` will
+ultimately need to be placed within `GUACAMOLE_HOME/extensions`, while the JDBC
+driver must be downloaded separately from the database vendor and placed within
+`GUACAMOLE_HOME/lib`.
+
+::::{tab} MySQL
+:::{list-table}
+:stub-columns: 1
+* - Guacamole extension
+ - `mysql/guacamole-auth-jdbc-mysql-1.3.0.jar`
+* - SQL schema scripts
+ - `mysql/schema/`
+* - JDBC driver
+ - *See below*
+:::
+
+Any of the following MySQL-compatible JDBC drivers are supported for connecting Guacamole with MySQL or MariaDB:
+
+* [MySQL Connector/J](http://dev.mysql.com/downloads/connector/j/)
+* [MariaDB Connector/J](https://mariadb.com/kb/en/about-mariadb-connector-j/)
+
+If using the JDBC driver from MySQL, the required `.jar` will be within a
+`.tar.gz` archive.
+::::
+
+::::{tab} PostgreSQL
+:::{list-table}
+:stub-columns: 1
+* - Guacamole extension
+ - `postgresql/guacamole-auth-jdbc-postgresql-1.3.0.jar`
+* - SQL schema scripts
+ - `postgresql/schema/`
+* - JDBC driver
+ - [PostgreSQL JDBC Driver](https://jdbc.postgresql.org/download.html#current)
+:::
+::::
+
+::::{tab} SQL Server
+:::{list-table}
+:stub-columns: 1
+* - Guacamole extension
+ - `sqlserver/guacamole-auth-jdbc-sqlserver-1.3.0.jar`
+* - SQL schema scripts
+ - `sqlserver/schema/`
+* - JDBC driver
+ - *See below*
+:::
+
+Any of the following TDS-compatible JDBC drivers are supported for connecting
+Guacamole to SQL Server:
+
+* [Microsoft JDBC Driver for SQL Server](https://docs.microsoft.com/en-us/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server)
+* [jTDS](http://jtds.sourceforge.net/)
+* [Progress DataDirect’s JDBC Driver for SQL Server](https://www.progress.com/jdbc/microsoft-sql-server)
+* Microsoft SQL Server 2000 JDBC Driver (legacy)
+::::
+
+(jdbc-auth-database-creation)=
+
+Creating the Guacamole database
+-------------------------------
+
+The database authentication module will need a database to store
+authentication data and a user to use only for data access and
+manipulation. You can use an existing database and existing user, but
+for the sake of simplicity and security, these instructions assume you
+will be creating a new database and new user that will be used only by
+Guacamole and only for this authentication module.
+
+You need MariaDB, MySQL, PostgreSQL, or SQL Server installed, and must
+have sufficient access to create and administer databases. If this is
+not the case, install your database of choice now. Most distributions
+will provide a convenient MySQL or PostgreSQL package which will set up
+everything for you, including the root database user, if applicable. If
+you're using SQL Server, you need to install the packages on your
+platform of choice, and also make sure that you obtain the proper
+licensing for the version and edition of SQL Server you are running.
+
+For the sake of clarity, these instructions will refer to the database
+as "guacamole_db", but the database can be named whatever you like.
+
+:::{tab} MySQL
+```console
+$ mysql -u root -p
+Enter password:
+Welcome to the MySQL monitor. Commands end with ; or \g.
+Your MySQL connection id is 233
+Server version: 5.5.29-0ubuntu0.12.10.1 (Ubuntu)
+
+Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+
+Oracle is a registered trademark of Oracle Corporation and/or its
+affiliates. Other names may be trademarks of their respective
+owners.
+
+Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
+
+mysql> CREATE DATABASE guacamole_db;
+Query OK, 1 row affected (0.00 sec)
+
+mysql> quit
+Bye
+$ ls schema/
+001-create-schema.sql 002-create-admin-user.sql upgrade
+$ cat schema/*.sql | mysql -u root -p guacamole_db
+Enter password:
+$
+```
+:::
+
+:::{tab} PostgreSQL
+```console
+$ createdb guacamole_db
+$ ls schema/
+001-create-schema.sql 002-create-admin-user.sql
+$ cat schema/*.sql | psql -d guacamole_db -f -
+CREATE TYPE
+CREATE TYPE
+CREATE TYPE
+CREATE TABLE
+CREATE INDEX
+...
+INSERT 0 1
+INSERT 0 4
+INSERT 0 3
+$
+```
+:::
+
+:::{tab} SQL Server
+```console
+$ /opt/mssql-tools/bin/sqlcmd -S localhost -U SA
+Password:
+1> CREATE DATABASE guacamole_db;
+2> GO
+1> quit
+$ /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -d guacamole_db -i schema/001-create-schema.sql
+Password:
+Rule bound to data type.
+The new rule has been bound to column(s) of the specified user data type.
+Rule bound to data type.
+The new rule has been bound to column(s) of the specified user data type.
+$ /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -d guacamole_db -i schema/002-create-admin-user.sql
+Password:
+
+(1 rows affected)
+
+(3 rows affected)
+
+(5 rows affected)
+$
+```
+:::
+
+Granting Guacamole access to the database
+-----------------------------------------
+
+For Guacamole to be able to execute queries against the database, you must
+create a new user for the database and grant that user sufficient privileges to
+manage the contents of all tables in the database. The user created for
+Guacamole needs only `SELECT`, `UPDATE`, `INSERT`, and `DELETE` permissions on
+all Guacamole tables. Additionally, if using PostgreSQL, the user will need
+`SELECT` and `USAGE` permission on all sequences within all Guacamole tables.
+*No other permissions should be granted.*
+
+These instructions will refer to the user as "guacamole_user" but the user can
+be named whatever you like. Naturally, you should also choose a real password
+for your user rather than the string "some_password" used as a placeholder
+below.
+
+:::{tab} MySQL
+```console
+$ mysql -u root -p
+Enter password:
+Welcome to the MySQL monitor. Commands end with ; or \g.
+Your MySQL connection id is 233
+Server version: 5.5.29-0ubuntu0.12.10.1 (Ubuntu)
+
+Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+
+Oracle is a registered trademark of Oracle Corporation and/or its
+affiliates. Other names may be trademarks of their respective
+owners.
+
+Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
+
+mysql> CREATE USER 'guacamole_user'@'localhost' IDENTIFIED BY 'some_password';
+Query OK, 0 rows affected (0.00 sec)
+
+mysql> GRANT SELECT,INSERT,UPDATE,DELETE ON guacamole_db.* TO 'guacamole_user'@'localhost';
+Query OK, 0 rows affected (0.00 sec)
+
+mysql> FLUSH PRIVILEGES;
+Query OK, 0 rows affected (0.02 sec)
+
+mysql> quit
+Bye
+$
+```
+:::
+
+:::{tab} PostgreSQL
+```console
+$ psql -d guacamole_db
+psql (9.3.6)
+Type "help" for help.
+
+guacamole=# CREATE USER guacamole_user WITH PASSWORD 'some_password';
+CREATE ROLE
+guacamole=# GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO guacamole_user;
+GRANT
+guacamole=# GRANT SELECT,USAGE ON ALL SEQUENCES IN SCHEMA public TO guacamole_user;
+GRANT
+guacamole=# \q
+$
+```
+:::
+
+:::{tab} SQL Server
+```console
+$ /opt/mssql-tools/bin/sqlcmd -S localhost -U SA
+Password:
+1> CREATE LOGIN guacamole_user WITH PASSWORD = 'some_password';
+2> GO
+1> USE guacamole_db;
+2> GO
+1> CREATE USER guacamole_user;
+2> GO
+1> ALTER ROLE db_datawriter ADD MEMBER guacamole_user;
+2> ALTER ROLE db_datareader ADD MEMBER guacamole_user;
+3> GO
+1> quit
+$
+```
+:::
+
+(jdbc-auth-installation)=
+
+Upgrading an existing Guacamole database
+----------------------------------------
+
+If you are upgrading from an older version of Guacamole, you may need to run
+one or more database schema upgrade scripts located within the
+`schema/upgrade/` directory. Each of these scripts is named
+{samp}`upgrade-pre-{VERSION}.sql` where `VERSION` is the version of Guacamole
+where those changes were introduced. They need to be run when you are upgrading
+from a version of Guacamole older than `VERSION`.
+
+If there are no {samp}`upgrade-pre-{VERSION}.sql` scripts present in the
+`schema/upgrade/` directory which apply to your existing Guacamole database,
+then the schema has not changed between your version and the version your are
+installing, and there is no need to run any database upgrade scripts.
+
+These scripts are incremental and, when relevant, *must be run in order*. For
+example, if you are upgrading an existing database from version
+0.9.13-incubating to version 1.0.0, you would need to run the
+`upgrade-pre-0.9.14.sql` script (because 0.9.13-incubating is older than
+0.9.14), followed by the `upgrade-pre-1.0.0.sql` script (because
+0.9.13-incubating is also older than 1.0.0).
+
+:::{important}
+Because the permissions granted to the Guacamole-specific PostgreSQL user when
+the database was first created will not automatically be granted for any new
+tables and sequences, you will also need to re-grant those permissions after
+applying any upgrade relevant scripts:
+
+```
+$ psql -d guacamole_db
+psql (9.3.6)
+Type "help" for help.
+
+guacamole=# GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO guacamole_user;
+GRANT
+guacamole=# GRANT SELECT,USAGE ON ALL SEQUENCES IN SCHEMA public TO guacamole_user;
+GRANT
+guacamole=# \q
+$
+```
+:::
+
+Installing database authentication
+----------------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located within
+the `GUACAMOLE_HOME/extensions` directory. To install the database
+authentication extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` and `GUACAMOLE_HOME/lib` directories,
+ if they do not already exist.
+
+2. Copy `guacamole-auth-jdbc-mysql-1.3.0.jar` *or*
+ `guacamole-auth-jdbc-postgresql-1.3.0.jar` *or*
+ `guacamole-auth-jdbc-sqlserver-1.3.0.jar` within
+ `GUACAMOLE_HOME/extensions`, depending on whether you are using
+ MySQL/MariaDB, PostgreSQL, or SQL Server.
+
+3. Copy the JDBC driver for your database to `GUACAMOLE_HOME/lib`. Without a
+ JDBC driver for your database, Guacamole will not be able to connect and
+ authenticate users.
+
+4. Configure Guacamole to use database authentication, as described below.
+
+:::{important}
+You will need to restart Guacamole by restarting your servlet container in
+order to complete the installation. Doing this will disconnect all active
+users, so be sure that it is safe to do so prior to attempting installation. If
+you do not configure the database authentication properly, Guacamole will not
+start up again until the configuration is fixed.
+:::
+
+(jdbc-auth-configuration)=
+
+### Configuring Guacamole for database authentication
+
+Additional properties must be added to `guacamole.properties` for Guacamole to
+properly connect to your database. These properties are specific to the
+database being used, and must be set correctly for authentication to work.
+
+The properties absolutely required by the database authentication extension are
+relatively few and self-explanatory, describing only how the connection to the
+database is to be established, and how Guacamole will authenticate when
+querying the database:
+
+:::{tab} MySQL
+`mysql-hostname`
+: The hostname or IP address of the server hosting your database.
+
+`mysql-database`
+: The name of the database that you created for Guacamole. This is given as
+ "guacamole_db" in the examples given in this chapter.
+
+`mysql-username`
+: The username of the user that Guacamole should use to connect to the
+ database. This is given as "guacamole_user" in the examples given in this
+ chapter.
+
+`mysql-password`
+: The password Guacamole should provide when authenticating with the database.
+ This is given as "some_password" in the examples given in this chapter.
+:::
+
+:::{tab} PostgreSQL
+`postgresql-hostname`
+: The hostname or IP address of the server hosting your database.
+
+`postgresql-database`
+: The name of the database that you created for Guacamole. This is given as
+ "guacamole_db" in the examples given in this chapter.
+
+`postgresql-username`
+: The username of the user that Guacamole should use to connect to the
+ database. This is given as "guacamole_user" in the examples given in this
+ chapter.
+
+`postgresql-password`
+: The password Guacamole should provide when authenticating with the database.
+ This is given as "some_password" in the examples given in this chapter.
+:::
+
+:::{tab} SQL Server
+`sqlserver-hostname`
+: The hostname or IP address of the server hosting your database.
+
+`sqlserver-database`
+: The name of the database that you created for Guacamole. This is given as
+ "guacamole_db" in the examples given in this chapter.
+
+`sqlserver-username`
+: The username of the user that Guacamole should use to connect to the
+ database. This is given as "guacamole_user" in the examples given in this
+ chapter.
+
+`sqlserver-password`
+: The password Guacamole should provide when authenticating with the database.
+ This is given as "some_password" in the examples given in this chapter.
+:::
+
+A minimal `guacamole.properties` configured to connect to a locally-hosted
+database would look like the following:
+
+:::{tab} MySQL
+```
+# MySQL properties
+mysql-hostname: localhost
+mysql-database: guacamole_db
+mysql-username: guacamole_user
+mysql-password: some_password
+```
+:::
+
+:::{tab} PostgreSQL
+```
+# PostgreSQL properties
+postgresql-hostname: localhost
+postgresql-database: guacamole_db
+postgresql-username: guacamole_user
+postgresql-password: some_password
+```
+:::
+
+:::{tab} SQL Server
+```
+# SQL Server properties
+sqlserver-hostname: localhost
+sqlserver-database: guacamole_db
+sqlserver-username: guacamole_user
+sqlserver-password: some_password
+```
+:::
+
+:::{important}
+Be sure to specify the correct username and password for the database user you
+created, and to specify the correct database. Authentication will not work if
+these parameters are not correct.
+:::
+
+Additional optional properties are available to control how Guacamole connects
+to the database server:
+
+:::{tab} MySQL
+`mysql-port`
+: The port number of the MySQL or MariaDB database to connect to. If not
+ specified, the standard MySQL / MariaDB port 3306 will be used.
+
+`mysql-driver`
+: Controls which JDBC driver the extension attempts to load and its
+ compatibility with various target database implementations. The extension
+ currently supports the following values for the `mysql-driver` property:
+
+ mysql
+ : The MySQL JDBC driver, known as Connector/J. This is the default.
+
+ mariadb
+ : The MariaDB JDBC driver.
+
+`mysql-server-timezone`
+: Specifies the timezone the MySQL server is configured to run in. While the
+ MySQL driver attempts to auto-detect the timezone in use by the server, there
+ are many cases where the timezone provided by the operating system is either
+ unknown by Java, or matches multiple timezones. In these cases MySQL may
+ either complain or refuse the connection unless the timezone is specified as
+ part of the connection. This property allows the timezone of the server to be
+ specified so that the connection can continue and the JDBC driver can
+ properly translate timestamps. The property accepts timezones in the
+ following formats:
+
+ Region/Locale
+ : Well-known TimeZone Identifiers, in the Region/Locale format. Examples are:
+
+ ```
+ mysql-server-timezone: America/Los_Angeles
+ mysql-server-timezone: Africa/Johannesburg
+ mysql-server-timezone: China/Shanghai
+ ```
+
+ GMT+/-HH:MM
+ : GMT or custom timezones specified by GMT offset. Examples of valid GMT
+ specifications are:
+
+ ```
+ mysql-server-timezone: GMT
+ mysql-server-timezone: GMT-00:00
+ mysql-server-timezone: GMT+0000
+ mysql-server-timezone: GMT-0
+ ```
+
+ Examples of custom timezones specified by GMT offsets are:
+
+ ```
+ mysql-server-timezone: GMT+0130
+ mysql-server-timezone: GMT-0430
+ mysql-server-timezone: GMT+06:00
+ mysql-server-timezone: GMT-9
+ ```
+
+ The MySQL Driver implements several parameters specific to
+ configuring SSL for secure connections to MySQL servers that support
+ or require encrypted communications. *Older versions of MySQL
+ Connector/J have known issues with SSL verification - if you
+ experience problems connecting to SSL-secured MySQL databases it is
+ recommended that you update to a current version of the driver.*
+
+`mysql-ssl-mode`
+: This property sets the SSL mode that the JDBC driver will attempt to use when
+ communicating with the remote MySQL server. The values for this property
+ match the standard values supported by the MySQL and MariaDB JDBC drivers:
+
+ disabled
+ : Do not use SSL, and fail if the server requires it. For compatibility this
+ will also set the legacy JDBC driver property useSSL to false.
+
+ preferred
+ : Prefer SSL, but fall back to plain-text if an SSL connection cannot be
+ negotiated. This is the default.
+
+ required
+ : Require SSL connections, and fail if SSL cannot be negotiated. This mode
+ does not perform any validition checks on the certificate in use by the
+ server, the issuer, etc.
+
+ verify-ca
+ : Require SSL connections, and check to make sure that the certificate issuer
+ is known to be valid.
+
+ verify-identity
+ : Require SSL connections, and check to make sure that the server certificate
+ is issued by a known authority, and that the identity of the server
+ matches the identity on the certificate.
+
+`mysql-ssl-trust-store`
+: The file that will store trusted SSL certificates for the JDBC driver to use
+ when validating CA and server certificates. This should be a JKS-formatted
+ certificate store. This property is optional and defaults to Java's normal
+ trusted certificate locations, which vary based on the version of Java in
+ use.
+
+`mysql-ssl-trust-password`
+: The password to use to access the SSL trusted certificate store, if one is
+ required. By default no password will be used.
+
+`mysql-ssl-client-store`
+: The file that contains the client certificate to use when making SSL
+ connections to the MySQL server. This should be a JKS-formatted certificate
+ store that contains a private key and certificate pair. This property is
+ optional, and by default no client certificate will be used for the SSL
+ connection.
+
+`mysql-ssl-client-password`
+: The password to use to access the client certificate store, if one is
+ required. By default no password will be used.
+:::
+
+:::{tab} PostgreSQL
+`postgresql-port`
+: The port number of the PostgreSQL database to connect to. If not specified,
+ the standard PostgreSQL port 5432 will be used.
+
+`postgresql-ssl-mode`
+: This property sets the SSL mode that the JDBC extension will attempt to use
+ when communicating with the remote Postgres server. The values for this
+ property match the standard values supported by the Postgres JDBC driver:
+
+ disable
+ : Do not use SSL, and fail if the server requires it.
+
+ allow
+ : If the server requires encryption use it, otherwise prefer unencrypted
+ connections.
+
+ prefer
+ : Try SSL connections, first, but allow unencrypted connections if the server
+ does not support SSL or if SSL negotiations fail. This is the
+ default.
+
+ require
+ : Require SSL connections, but implicitly trust all server certificates and
+ authorities.
+
+ verify-ca
+ : Require SSL connections, and verify that the server certificate is issued
+ by a known certificate authority.
+
+ verify-full
+ : Require SSL connections, verifying that the server certificate is issued
+ by a known authority, and that the name on the certificate matches the name of
+ the server.
+
+`postgresql-ssl-cert-file`
+: The file containing the client certificate to be used when making an
+ SSL-encrtyped connection to the Postgres server, in PEM format. This property
+ is optional, and will be ignored if the SSL mode is set to disable.
+
+`postgresql-ssl-key-file`
+: The file containing the client private key to be used when making an
+ SSL-encrypted connection to the Postgres server, in PEM format. This property
+ is optional, and will be ignored if the SSL mode is set to disable.
+
+`postgresql-ssl-root-cert-file`
+: The file containing the root and intermedidate certificates against which the
+ server certificate will be verified when making an SSL-encrypted connection to
+ the Postgres server. This file should contain one or more PEM-formatted
+ authority certificates. This property is optional, and will only be used if SSL
+ mode is set to verify-ca or verify-full.
+
+ If SSL is set to one of the verification modes and this property is not
+ specified, the JDBC driver will attempt to use the `.postgresql/root.crt`
+ file from the home directory of the user running the web application server
+ (e.g. Tomcat). If this property is not specified and the default file does
+ not exist, the Postgres JDBC driver will fail to connect to the server.
+
+`postgresql-ssl-key-password`
+: The password that will be used to access the client private key file, if the
+ client private key is encrypted. This property is optional, and is only used if
+ the `postgresql-ssl-key-file` property is set and SSL is enabled.
+
+`postgresql-default-statement-timeout`
+: The number of seconds the driver will wait for a response from the database,
+ before aborting the query. A value of 0 (the default) means the timeout is
+ disabled.
+
+`postgresql-socket-timeout`
+: The number of seconds to wait for socket read operations. If reading from the
+ server takes longer than this value, the connection will be closed. This can
+ be used to handle network problems such as a dropped connection to the
+ database. Similar to `postgresql-default-statement-timeout`, it will also
+ abort queries that take too long. A value of 0 (the default) means the
+ timeout is disabled.
+:::
+
+:::{tab} SQL Server
+`sqlserver-port`
+: The port number of the SQL Server database to connect to. If not specified,
+ the standard SQL Server port 1433 will be used.
+
+`sqlserver-driver`
+: The specific TDS-compatible JDBC driver to expect to have been installed.
+ Multiple JDBC drivers are available that support SQL Server. If not using the
+ Microsoft driver, this property must be specified to define the driver that
+ will be used. Possible values are:
+
+ microsoft2005
+ : The current [Microsoft JDBC Driver for SQL Server](https://docs.microsoft.com/en-us/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server),
+ supporting SQL Server 2005 and later. This is the default.
+
+ microsoft
+ : The legacy Microsoft driver for SQL Server 2000.
+
+ jtds
+ : The open source [jTDS](http://jtds.sourceforge.net/) driver.
+
+ datadirect
+ : [Progress DataDirect’s JDBC Driver for SQL Server](https://www.progress.com/jdbc/microsoft-sql-server).
+
+`sqlserver-instance`
+: The instance name that the SQL Server driver should attempt to connect to, if
+ not the default SQL Server instance. This instance name is configured during
+ the SQL Server installation. This property is optional, and most installations
+ should work without the need to specify an instance name.
+:::
+
+#### Enforcing password policies
+
+Configuration options are available for enforcing rules intended to encourage
+password complexity and regular changing of passwords. None of these options
+are enabled by default, but can be selectively enabled through additional
+properties in `guacamole.properties`.
+
+##### Password complexity
+
+Administrators can require that passwords have a certain level of complexity,
+such as having both uppercase and lowercase letters ("multiple case"), at least
+one digit, or at least one symbol, and can prohibit passwords from containing
+the user's own username.
+
+With respect to password content, the database authentication defines a "digit"
+as any numeric character and a "symbol" is any non-alphanumeric character. This
+takes non-English languages into account, thus a digit is not simply "0"
+through "9" but rather [any character defined in Unicode as
+numeric](https://en.wikipedia.org/wiki/Numerals_in_Unicode), and a symbol is
+any character which Unicode does not define as alphabetic or numeric.
+
+The check for whether a password contains the user's own username is performed
+in a case-insensitive manner. For example, if the user's username is "phil",
+the passwords "ch!0roPhil" and "PHIL-o-dendr0n" would still be prohibited.
+
+:::{tab} MySQL
+```
+mysql-user-password-min-length: 8
+mysql-user-password-require-multiple-case: true
+mysql-user-password-require-symbol: true
+mysql-user-password-require-digit: true
+mysql-user-password-prohibit-username: true
+```
+:::
+
+:::{tab} PostgreSQL
+```
+postgresql-user-password-min-length: 8
+postgresql-user-password-require-multiple-case: true
+postgresql-user-password-require-symbol: true
+postgresql-user-password-require-digit: true
+postgresql-user-password-prohibit-username: true
+```
+:::
+
+:::{tab} SQL Server
+```
+sqlserver-user-password-min-length: 8
+sqlserver-user-password-require-multiple-case: true
+sqlserver-user-password-require-symbol: true
+sqlserver-user-password-require-digit: true
+sqlserver-user-password-prohibit-username: true
+```
+:::
+
+##### Password age / expiration
+
+"Password age" refers to two separate concepts:
+
+1. Requiring users to change their password after a certain amount of time has
+ elapsed since the last password change (maximum password age).
+
+2. Preventing users from changing their password too frequently (minimum
+ password age).
+
+While it may seem strange to prevent users from changing their password too
+frequently, it does make sense if you are concerned that rapid password changes
+may defeat password expiration (users could immediately change the password
+back) or tracking of password history (users could cycle through passwords
+until the history is exhausted and their old password is usable again).
+
+By default, the database authentication does not apply any limits to password
+age, and users with permission to change their passwords may do so as
+frequently or infrequently as they wish. Password age limits can be enabled
+using a pair of properties, each accepting values given in units of days:
+
+:::{tab} MySQL
+```
+mysql-user-password-min-age: 7
+mysql-user-password-max-age: 90
+```
+:::
+
+:::{tab} PostgreSQL
+```
+postgresql-user-password-min-age: 7
+postgresql-user-password-max-age: 90
+```
+:::
+
+:::{tab} SQL Server
+```
+sqlserver-user-password-min-age: 7
+sqlserver-user-password-max-age: 90
+```
+:::
+
+:::{important}
+So that administrators can always intervene in the case that a password needs
+to be reset despite restrictions, the minimum age restriction does not apply to
+any user with permission to administer the system.
+:::
+
+##### Preventing password reuse
+
+If desired, Guacamole can keep track of each user's most recently used
+passwords, and will prohibit reuse of those passwords until the password has
+been changed sufficiently many times. By default, Guacamole will not keep track
+of old passwords.
+
+Note that these passwords are hashed in the same manner as each user's current
+password. When a user's password is changed, the hash, salt, etc. currently
+stored for that user is actually just copied verbatim (along with a timestamp)
+into a list of historical passwords, with older entries from this list being
+automatically deleted.
+
+:::{tab} MySQL
+```
+mysql-user-password-history-size: 6
+```
+:::
+
+:::{tab} PostgreSQL
+```
+postgresql-user-password-history-size: 6
+```
+:::
+
+:::{tab} SQL Server
+```
+sqlserver-user-password-history-size: 6
+```
+:::
+
+(jdbc-auth-concurrency)=
+
+#### Concurrent use of Guacamole connections
+
+The database authentication module provides configuration options to restrict
+concurrent use of connections or connection groups. These options are set
+through `guacamole.properties` and specify the default concurrency policies for
+connections and connection groups. The values set through the properties can be
+overridden later on a per-connection basis using the administrative interface:
+
+:::{tab} MySQL
+```
+mysql-default-max-connections: 1
+mysql-default-max-group-connections: 1
+```
+:::
+
+:::{tab} PostgreSQL
+```
+postgresql-default-max-connections: 1
+postgresql-default-max-group-connections: 1
+```
+:::
+
+:::{tab} SQL Server
+```
+sqlserver-default-max-connections: 1
+sqlserver-default-max-group-connections: 1
+```
+:::
+
+These properties are not required, but with the above properties in place,
+users attempting to use a connection or group that is already in use will be
+denied access. By default, concurrent access is allowed.
+
+Concurrent access can also be restricted such that a particular user may only
+use a connection or group a certain number of times. By default, per-user
+concurrent use is limited for connection groups (to avoid allowing a single
+user to exhaust the contents of the group) but otherwise unrestricted. This
+default behavior can be modified through `guacamole.properties` or the
+per-connection settings exposed in the administrative interface:
+
+:::{tab} MySQL
+```
+mysql-default-max-connections-per-user: 0
+mysql-default-max-group-connections-per-user: 0
+```
+:::
+
+:::{tab} PostgreSQL
+```
+postgresql-default-max-connections-per-user: 0
+postgresql-default-max-group-connections-per-user: 0
+```
+:::
+
+:::{tab} SQL Server
+```
+sqlserver-default-max-connections-per-user: 0
+sqlserver-default-max-group-connections-per-user: 0
+```
+:::
+
+If you wish to impose an absolute limit on the number of connections that can
+be established through Guacamole, ignoring which users or connections are
+involved, this can be done as well. By default, Guacamole will impose no such
+limit:
+
+:::{tab} MySQL
+```
+mysql-absolute-max-connections: 0
+```
+:::
+
+:::{tab} PostgreSQL
+```
+postgresql-absolute-max-connections: 0
+```
+:::
+
+:::{tab} SQL Server
+```
+sqlserver-absolute-max-connections: 0
+```
+:::
+
+(jdbc-auth-restrict)=
+
+### Restricting authentication to database users only
+
+By default, users will be allowed access to Guacamole as long as they are
+authenticated by at least one extension. If database authentication is in use,
+and a user is not associated with the database, then that user will be allowed
+access to Guacamole if another extension grants this access, and will be
+provided with a view of the data exposed by other extensions for that user
+account.
+
+In some situations, such as when [combining LDAP with a
+database](ldap-and-database), it would be preferable to let the database have
+the last word regarding whether a user should be allowed into the system:
+restricting access to only those users which exist in the database, and
+explicitly denying authentication through all other means unless that user has
+been associated with the database as well. This behavior can be forced by
+setting properties which declare that database user accounts are required:
+
+:::{tab} MySQL
+```
+mysql-user-required: true
+```
+:::
+
+:::{tab} PostgreSQL
+```
+postgresql-user-required: true
+```
+:::
+
+:::{tab} SQL Server
+```
+sqlserver-user-required: true
+```
+:::
+
+With the above properties set, successful authentication attempts for users
+which are not associated with the database will be vetoed by the database
+authentication. Guacamole will report that the login is invalid, as if the user
+does not exist at all.
+
+(jdbc-auth-auto-create)=
+
+### Auto-creating database users
+
+Guacamole supports the ability to layer authentication modules on top of one
+another such that users successfully authenticated from one extension (e.g.
+LDAP) can be assigned permissions to connections in another extension (e.g.
+JDBC). Other extensions, like the TOTP extension, rely on the database
+extension to be able to store information for various user accounts. In these
+situations it can be difficult to have to manually create user accounts within
+the database extension.
+
+The database extension provides a mechanism for enabling auto-creation of user
+accounts that successfully authenticate from other extensions. This
+functionality is disabled by default, but can be enabled in each of the
+supported database extensions by enabling the appropriate option in
+`guacamole.properties`. The resulting accounts will only have `READ` access to
+themselves until additional permissions are granted, either explicitly by the
+administrator or by permissions assigned to groups of which the user is a
+member.
+
+:::{tab} MySQL
+```
+mysql-auto-create-accounts: true
+```
+:::
+
+:::{tab} PostgreSQL
+```
+postgresql-auto-create-accounts: true
+```
+:::
+
+:::{tab} SQL Server
+```
+sqlserver-auto-create-accounts: true
+```
+:::
+
+### Completing the installation
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before the database authentication will take effect. Restart your servlet
+container and give the new authentication a try.
+
+:::{important}
+You only need to restart your servlet container. *You do not need to restart
+guacd*.
+
+guacd is completely independent of the web application and does not deal with
+`guacamole.properties` or the authentication system in any way. Since you are
+already restarting the servlet container, restarting guacd as well technically
+won't hurt anything, but doing so is completely pointless.
+:::
+
+If Guacamole does not come back online after restarting your servlet container,
+check the logs. Problems in the configuration of the database authentication
+extension will prevent Guacamole from starting up, and any such errors will be
+recorded in the logs of your servlet container.
+
+(jdbc-auth-default-user)=
+
+Logging in
+----------
+
+The default Guacamole user created by the provided SQL scripts is
+"`guacadmin`", with a default password of "`guacadmin`". Once you have verified
+that the database authentication is working, *you should change your password
+immediately*.
+
+More detailed instructions for managing users and connections is given in
+[](administration).
+
+(jdbc-auth-schema)=
+
+Modifying data manually
+-----------------------
+
+If necessary, it is possible to modify the data backing the authentication
+module manually by executing SQL statements against the database. In general
+use, this will not be common, but if you need to bulk-insert a large number of
+users or connections, or you wish to translate an existing configuration
+automatically, you will need to know how everything is laid out at a high
+level.
+
+This section assumes knowledge of SQL and your chosen database, and that
+whatever you need to do can be accomplished if only you had high-level
+information about Guacamole's SQL schema.
+
+(jdbc-auth-schema-entities)=
+
+### Entities
+
+Every user and user group has a corresponding entry in the `guacamole_entity`
+table which serves as the basis for assignment of a unique name, permissions,
+as well as relations which are common to both users and groups like group
+membership. Each entity has a corresponding name which is unique across all
+other entities of the same type.
+
+If deleting a user or user group, the corresponding entity should also be
+deleted. As any user or group which points to the entity will be deleted
+automatically when the entity is deleted through cascading deletion, *it is
+advisable to use the entity as the basis for any delete operation*.
+
+The `guacamole_entity` table contains the following columns:
+
+`entity_id`
+: The unique integer associated with each entity (user or user group). This
+ value is generated automatically when a new entry is inserted into the
+ `guacamole_entity` table and is distinct from the unique integer associated
+ with the user entry in [`guacamole_user`](jdbc-auth-schema-users) or the user
+ group entry in [`guacamole_user_group`](jdbc-auth-schema-groups).
+
+`name`
+: The unique name associated with each user or group. This value must be
+ specified manually, and must be different from any existing user or group in
+ the table. The name need only be unique relative to the names of other entities
+ having the same type (a user may have the same name as a group).
+
+`type`
+: The type of this entity. This can be either `USER` or `USER_GROUP`.
+
+(jdbc-auth-schema-users)=
+
+### Users
+
+Every user has a corresponding entry in the `guacamole_user` and
+[`guacamole_entity`](jdbc-auth-schema-entities) tables. Each user has a
+corresponding unique username, specified via `guacamole_entity`, and salted
+password. The salted password is split into two columns: one containing the
+salt, and the other containing the password hashed with SHA-256.
+
+If deleting a user, the [corresponding entity](jdbc-auth-schema-entities)
+should also be deleted. As any user which points to the entity will be deleted
+automatically when the entity is deleted through cascading deletion, *it is
+advisable to use the entity as the basis for any delete operation*.
+
+The `guacamole_user` table contains the following columns:
+
+`user_id`
+: The unique integer associated with each user. This value is generated
+ automatically when a new entry is inserted into the `guacamole_user` table.
+
+`entity_id`
+: The value of the `entity_id` column of the `guacamole_entity` entry
+ representing this user.
+
+`password_hash`
+: The result of hashing the user's password concatenated with the contents of
+ `password_salt` using SHA-256. The salt is appended to the password prior to
+ hashing.
+
+ Although passwords set through Guacamole will always be salted, it is
+ possible to use unsalted password hashes when inserted manually or through an
+ external system. If `password_salt` is `NULL`, the `password_hash` will be
+ handled as a simple unsalted hash of the password.
+
+`password_salt`
+: A 32-byte random value. When a new user is created from the web interface,
+ this value is randomly generated using a cryptographically-secure random
+ number generator.
+
+ This will always be set for users whose passwords are set through Guacamole,
+ but it is possible to use unsalted password hashes when inserted manually or
+ through an external system. If `password_salt` is `NULL`, the `password_hash`
+ will be handled as a simple unsalted hash of the password.
+
+`password_date`
+: The date (and time) that the password was last changed. When a password is
+ changed via the Guacamole interface, this value is updated. This, along with
+ the contents of the `guacamole_user_password_history` table, is used to
+ enforce password policies.
+
+`disabled`
+: Whether login attempts as this user account should be rejected. If this
+ column is set to `TRUE` or `1`, login attempts by this user will be rejected
+ as if the user did not exist. By default, user accounts are not disabled, and
+ login attempts will succeed if the user provides the correct password.
+
+`expired`
+: If set to `TRUE` or `1`, requires that the user reset their password prior to
+ fully logging in. The user will be presented with a password reset form, and
+ will not be allowed to log into Guacamole until the password has been changed.
+ By default, user accounts are not expired, and no password reset will be
+ required upon login.
+
+`access_window_start`
+: The time of day (not date) after which this user account may be used. If
+ `NULL`, this restriction does not apply. If set to non-`NULL`, attempts to log
+ in after the specified time will be allowed, while attempts to log in before
+ the specified time will be denied.
+
+`access_window_end`
+: The time of day (not date) after which this user account may *not* be used.
+ If `NULL`, this restriction does not apply. If set to non-`NULL`, attempts to
+ log in after the specified time will be denied, while attempts to log in
+ before the specified time will be allowed.
+
+`valid_from`
+: The date (not time of day) after which this user account may be used. If
+ `NULL`, this restriction does not apply. If set to non-`NULL`, attempts to
+ log in after the specified date will be allowed, while attempts to log in
+ before the specified date will be denied.
+
+`valid_until`
+: The date (not time of day) after which this user account may *not* be used.
+ If `NULL`, this restriction does not apply. If set to non-`NULL`, attempts to
+ log in after the specified date will be denied, while attempts to log in
+ before the specified date will be allowed.
+
+`timezone`
+: The time zone to use when interpreting the `access_window_start`,
+ `access_window_end`, `valid_from`, and `valid_until` values. This value may
+ be any Java `TimeZone` ID, as defined by
+ [`getAvailableIDs()`](http://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html#getAvailableIDs())
+ though the Guacamole management interface will only present a subset of these
+ time zones.
+
+`full_name`
+: The user's full name. Unlike the username, this name need not be unique; it
+ is optional and is meant for display purposes only. Defining this value has
+ no bearing on user identity, which is dictated purely by the username. User
+ accounts with no associated full name should have this column set to `NULL`.
+
+`email_address`
+: The user's email address, if any. This value is optional, need not be unique
+ relative to other defined users, and is meant for display purposes only.
+ Defining this value has no bearing on user identity, which is dictated purely
+ by the username. If the user has no associated email address, this column
+ should be set to `NULL`.
+
+`organization`
+: The name of the organization, company, etc. that the user is affiliated with.
+ This value is optional and is meant for display purposes only. Defining this
+ value has no bearing on user identity, which is dictated purely by the
+ username. Users with no associated organization should have this column set
+ to `NULL`.
+
+`organizational_role`
+: The role or title of the user at the organization described by the
+ organization column. This value is optional and is used for display purposes
+ only. Defining this value has no bearing on user identity, which is dictated
+ purely by the username. Users with no associated organization (or specific
+ role/title at that organization) should have this column set to `NULL`.
+
+:::{important}
+If you choose to manually set unsalted password hashes, please be sure you
+understand the security implications of doing so.
+
+In the event that your database is compromised, finding the password for a
+*salted* hash is computationally infeasible, but finding the password for an
+*unsalted* hash is often not. In many cases, the password which corresponds to
+an unsalted hash can be found simply by entering the hash into a search engine
+like Google.
+:::
+
+If creating a user manually, the main complication is the salt, which must be
+determined before the `INSERT` statement can be constructed, but this can be
+dealt with using variables. For MySQL:
+
+```mysql
+-- Generate salt
+SET @salt = UNHEX(SHA2(UUID(), 256));
+
+-- Create base entity entry for user
+INSERT INTO guacamole_entity (name, type)
+VALUES ('myuser', 'USER');
+
+-- Create user and hash password with salt
+INSERT INTO guacamole_user (
+ entity_id,
+ password_salt,
+ password_hash,
+ password_date
+)
+SELECT
+ entity_id,
+ @salt,
+ UNHEX(SHA2(CONCAT('mypassword', HEX(@salt)), 256)),
+ CURRENT_TIMESTAMP
+FROM guacamole_entity
+WHERE
+ name = 'myuser'
+ AND type = 'USER';
+```
+
+This sort of statement is useful for both creating new users or for changing
+passwords, especially if all administrators have forgotten theirs.
+
+If you are not using MySQL, or you are using a version of MySQL that lacks the
+SHA2 function, you will need to calculate the SHA-256 value manually (by using
+the `sha256sum` command, for example).
+
+(jdbc-auth-schema-password-history)=
+
+#### Password history
+
+When a user's password is changed, a copy of the previous password's
+hash and salt is made within the `guacamole_user_password_history`.
+Each entry in this table is associated with the user whose password
+changed, along with the date that password first applied.
+
+Old entries within this table are automatically deleted on a per-user
+basis depending on the requirements of the password policy. For example,
+if the password policy has been configured to require that users not
+reuse any of their previous six passwords, then there will be no more
+than six entries in this table for each user.
+
+`password_history_id`
+: The unique integer associated with each password history record. This
+ value is generated automatically when a new entry is inserted into the
+ `guacamole_user_password_history` table.
+
+`user_id`
+: The value of the `user_id` column from the entry in `guacamole_user`
+ associated with the user who previously had this password.
+
+`password_hash`
+: The hashed password specified within the `password_hash` column of
+ `guacamole_user` prior to the password being changed.
+
+ In most cases, this will be a salted hash, though it is possible to force
+ the use of unsalted hashes when making changes to the database manually or
+ through an external system.
+
+`password_salt`
+: The salt value specified within the `password_salt` column of
+ `guacamole_user` prior to the password being changed.
+
+ This will always be set for users whose passwords are set through
+ Guacamole, but it is possible to use unsalted password hashes when
+ inserted manually or through an external system, in which case this may be
+ `NULL`.
+
+`password_date`
+: The date (and time) that the password was set. The time that the password
+ ceased being used is recorded either by the `password_date` of the next
+ related entry in `guacamole_user_password_history` or `password_date` of
+ `guacamole_user` (if there is no such history entry).
+
+(jdbc-auth-schema-login-history)=
+
+#### Login history
+
+When a user logs in or out, a corresponding entry in the
+`guacamole_user_history` table is created or updated respectively.
+Each entry is associated with the user that logged in and the time their
+session began. If the user has logged out, the time their session ended
+is also stored.
+
+It is very unlikely that a user will need to update this table, but
+knowing the structure is potentially useful if you wish to generate a
+report of Guacamole usage. The `guacamole_user_history` table has the
+following columns:
+
+`history_id`
+: The unique integer associated with each history record. This value is
+ generated automatically when a new entry is inserted into the
+ `guacamole_user_history` table.
+
+`user_id`
+: The value of the `user_id` from the entry in `guacamole_user` associated
+ with the user that logged in. If the user no longer exists, this will be
+ `NULL`.
+
+`username`
+: The username associated with the user at the time that they logged in.
+ This username value is not guaranteed to uniquely identify a user, as the
+ original user may be subsequently renamed or deleted.
+
+`remote_host`
+: The hostname or IP address of the machine that the user logged in from, if
+ known. If unknown, this will be `NULL`.
+
+`start_date`
+: The time at which the user logged in. Despite its name, this column also
+ stores time information in addition to the date.
+
+`end_date`
+: The time at which the user logged out. If the user is still active, the
+ value in this column will be `NULL`. Despite its name, this column also
+ stores time information in addition to the date.
+
+(jdbc-auth-schema-groups)=
+
+### User groups
+
+Similar to [users](jdbc-auth-schema-users), every user group has a
+corresponding entry in the `guacamole_user_group` and
+[`guacamole_entity`](jdbc-auth-schema-entities) tables. Each user group has a
+corresponding unique name specified via `guacamole_entity`.
+
+If deleting a user group, the [corresponding entity](jdbc-auth-schema-entities)
+should also be deleted. As any user group which points to the entity will be
+deleted automatically when the entity is deleted through cascading deletion,
+*it is advisable to use the entity as the basis for any delete operation*.
+
+The `guacamole_user_group` table contains the following columns:
+
+`user_group_id`
+: The unique integer associated with each user group. This value is
+ generated automatically when a new entry is inserted into the
+ `guacamole_user_group` table.
+
+`entity_id`
+: The value of the `entity_id` column of the `guacamole_entity` entry
+ representing this user group.
+
+`disabled`
+: Whether membership within this group should be taken into account when
+ determining the permissions granted to a particular user. If this column
+ is set to `TRUE` or `1`, membership in this group will have no effect on
+ user permissions, whether those permissions are granted to this group
+ directly or indirectly through the groups that this group is a member of.
+ By default, user groups are not disabled, and permissions granted to a
+ user through the group will be taken into account.
+
+Membership within a user group is dictated through entries in the
+`guacamole_user_group_member` table. As both users and user groups may be
+members of groups, each entry associates the containing group with the entity
+of the member.
+
+The `guacamole_user_group_member` table contains the following columns:
+
+`user_group_id`
+: The `user_group_id` value of the user group having the specified member.
+
+`member_entity_id`
+: The `entity_id` value of the user or user group that is a member of the
+ specified group.
+
+(jdbc-auth-schema-connections)=
+
+### Connections and parameters
+
+Each connection has an entry in the `guacamole_connection` table, with a
+one-to-many relationship to parameters, stored as name/value pairs in the
+`guacamole_connection_parameter` table.
+
+The `guacamole_connection` table is simply a pairing of a unique and
+descriptive name with the protocol to be used for the connection. It contains
+the following columns:
+
+`connection_id`
+: The unique integer associated with each connection. This value is
+ generated automatically when a new entry is inserted into the
+ `guacamole_connection` table.
+
+`connection_name`
+: The unique name associated with each connection. This value must be
+ specified manually, and must be different from any existing connection
+ name in the same connection group. References to connections in other
+ tables use the value from `connection_id`, not `connection_name`.
+
+`protocol`
+: The protocol to use with this connection. This is the name of the protocol
+ that should be sent to guacd when connecting, for example "`vnc`" or
+ "`rdp`".
+
+`parent_id`
+: The unique integer associated with the connection group containing this
+ connection, or `NULL` if this connection is within the root group.
+
+`max_connections`
+: The maximum number of concurrent connections to allow to this connection
+ at any one time *regardless of user*. `NULL` will use the default value
+ specified in `guacamole.properties` and a value of `0` denotes unlimited.
+
+`max_connections_per_user`
+: The maximum number of concurrent connections to allow to this connection
+ at any one time *from a single user*. `NULL` will use the default value
+ specified in `guacamole.properties` and a value of `0` denotes unlimited.
+
+`proxy_hostname`
+: The hostname or IP address of the Guacamole proxy daemon (guacd) which
+ should be used for this connection. If `NULL`, the value defined with the
+ `guacd-hostname` property in `guacamole.properties` will be used.
+
+`proxy_port`
+: The TCP port number of the Guacamole proxy daemon (guacd) which should be
+ used for this connection. If `NULL`, the value defined with the
+ `guacd-port` property in `guacamole.properties` will be used.
+
+`proxy_encryption_method`
+: The encryption method which should be used when communicating with the
+ Guacamole proxy daemon (guacd) for this connection. This can be either
+ `NONE`, for no encryption, or `SSL`, for SSL/TLS. If `NULL`, the
+ encryption method will be dictated by the `guacd-ssl` property in
+ `guacamole.properties`.
+
+`connection_weight`
+: The weight for a connection, used for applying weighted load balancing
+ algorithms when connections are part of a `BALANCING` group. This is an
+ integer value, where values `1` or greater will weight the connection
+ relative to other connections in that group, and values below `1` cause
+ the connection to be disabled in the group. If `NULL`, the connection will
+ be assigned a default weight of `1`.
+
+`failover_only`
+: Whether this connection should be used for failover situations only, also
+ known as a "hot spare". If this column is set to `TRUE` or `1`, this
+ connection will be used only when another connection within the same
+ `BALANCING` connection group has failed due to an error within the remote
+ desktop.
+
+ *Connection groups will always transparently switch to the next available
+ connection in the event of remote desktop failure, regardless of the value
+ of this column.* This column simply dictates whether a particular
+ connection should be *reserved* for such situations, and left unused
+ otherwise.
+
+ This column only has an effect on connections within `BALANCING` groups.
+
+As there are potentially multiple parameters per connection, where the names of
+each parameter are completely arbitrary and determined only by the protocol in
+use, every parameter for a given connection has an entry in table
+`guacamole_connection_parameter` table associated with its corresponding
+connection. This table contains the following columns:
+
+`connection_id`
+: The `connection_id` value from the connection this parameter is for.
+
+`parameter_name`
+: The name of the parameter to set. This is the name listed in the
+ documentation for the protocol specified in the associated connection.
+
+`parameter_value`
+: The value to assign to the parameter named. While this value is an
+ arbitrary string, it must conform to the requirements of the protocol as
+ documented for the connection to be successful.
+
+Adding a connection and corresponding parameters is relatively easy compared to
+adding a user as there is no salt to generate nor password to hash:
+
+```mysql
+-- Create connection
+INSERT INTO guacamole_connection (connection_name, protocol) VALUES ('test', 'vnc');
+
+-- Determine the connection_id
+SELECT * FROM guacamole_connection WHERE connection_name = 'test' AND parent_id IS NULL;
+
+-- Add parameters to the new connection
+INSERT INTO guacamole_connection_parameter VALUES (1, 'hostname', 'localhost');
+INSERT INTO guacamole_connection_parameter VALUES (1, 'port', '5901');
+```
+
+(jdbc-auth-schema-connection-history)=
+
+#### Usage history
+
+When a connection is initiated or terminated, a corresponding entry in the
+`guacamole_connection_history` table is created or updated respectively. Each
+entry is associated with the user using the connection, the connection itself,
+the [sharing profile](jdbc-auth-schema-sharing-profiles) in use (if the
+connection is being shared), and the time the connection started. If the
+connection has ended, the end time is also stored.
+
+It is very unlikely that a user will need to update this table, but knowing the
+structure is potentially useful if you wish to generate a report of Guacamole
+usage. The `guacamole_connection_history` table has the following columns:
+
+`history_id`
+: The unique integer associated with each history record. This value is
+ generated automatically when a new entry is inserted into the
+ `guacamole_connection_history` table.
+
+`user_id`
+: The value of the `user_id` from the entry in `guacamole_user` associated
+ with the user using the connection. If the user no longer exists, this
+ will be `NULL`.
+
+`username`
+: The username associated with the user at the time that they used the
+ connection. This username value is not guaranteed to uniquely identify a
+ user, as the original user may be subsequently renamed or deleted.
+
+`connection_id`
+: The value of the `connection_id` from the entry in `guacamole_connection`
+ associated the connection being used. If the connection associated with
+ the history record no longer exists, this will be `NULL`.
+
+`connection_name`
+: The name associated with the connection at the time that it was used.
+
+`sharing_profile_id`
+: The value of the `sharing_profile_id` from the entry in
+ `guacamole_sharing_profile` associated the sharing profile being used to
+ access the connection. If the connection is not being shared (no sharing
+ profile is being used), or if the sharing profile associated with the
+ history record no longer exists, this will be `NULL`.
+
+`sharing_profile_name`
+: The name associated with the sharing profile being used to access the
+ connection at the time this history entry was recorded. If the connection
+ is not being shared, this will be `NULL`.
+
+`start_date`
+: The time at which the connection was started by the user specified.
+ Despite its name, this column also stores time information in addition to
+ the date.
+
+`end_date`
+: The time at which the connection ended. If the connection is still active,
+ the value in this column will be `NULL`. Despite its name, this column
+ also stores time information in addition to the date.
+
+(jdbc-auth-schema-sharing-profiles)=
+
+### Sharing profiles and parameters
+
+Each sharing profile has an entry in the `guacamole_sharing_profile` table,
+with a one-to-many relationship to parameters, stored as name/value pairs in
+the `guacamole_sharing_profile_parameter` table.
+
+The `guacamole_sharing_profile` table is simply a pairing of a unique and
+descriptive name with the connection that can be shared using the sharing
+profile, also known as the "primary connection". It contains the following
+columns:
+
+`sharing_profile_id`
+: The unique integer associated with each sharing profile. This value is
+ generated automatically when a new entry is inserted into the
+ `guacamole_sharing_profile` table.
+
+`sharing_profile_name`
+: The unique name associated with each sharing profile. This value must be
+ specified manually, and must be different from any existing sharing
+ profile name associated with the same primary connection. References to
+ sharing profiles in other tables use the value from `sharing_profile_id`,
+ not `sharing_profile_name`.
+
+`primary_connection_id`
+: The unique integer associated with the primary connection. The "primary
+ connection" is the connection which can be shared using this sharing
+ profile.
+
+As there are potentially multiple parameters per sharing profile, where the
+names of each parameter are completely arbitrary and determined only by the
+protocol associated with the primary connection, every parameter for a given
+sharing profile has an entry in the `guacamole_sharing_profile_parameter` table
+associated with its corresponding sharing profile. This table contains the
+following columns:
+
+`sharing_profile_id`
+: The `sharing_profile_id` value from the entry in the
+ `guacamole_sharing_profile` table for the sharing profile this parameter
+ applies to.
+
+`parameter_name`
+: The name of the parameter to set. This is the name listed in the
+ documentation for the protocol of the primary connection of the associated
+ sharing profile.
+
+`parameter_value`
+: The value to assign to the parameter named. While this value is an
+ arbitrary string, it must conform to the requirements of the protocol as
+ documented.
+
+(jdbc-auth-schema-connection-groups)=
+
+### Connection groups
+
+Each connection group has an entry in the `guacamole_connection_group` table,
+with a one-to-many relationship to other groups and connections.
+
+The `guacamole_connection_group` table is simply a pairing of a unique and
+descriptive name with a group type, which can be either `ORGANIZATIONAL` or
+`BALANCING`. It contains the following columns:
+
+`connection_group_id`
+: The unique integer associated with each connection group. This value is
+ generated automatically when a new entry is inserted into the
+ `guacamole_connection_group` table.
+
+`connection_group_name`
+: The unique name associated with each connection group. This value must be
+ specified manually, and must be different from any existing connection
+ group name in the same connection group. References to connections in
+ other tables use the value from `connection_group_id`, not
+ `connection_group_name`.
+
+`type`
+: The type of this connection group. This can be either `ORGANIZATIONAL` or
+ `BALANCING`.
+
+`parent_id`
+: The unique integer associated with the connection group containing this
+ connection group, or `NULL` if this connection group is within the root
+ group.
+
+`max_connections`
+: The maximum number of concurrent connections to allow to this connection
+ group at any one time *regardless of user*. `NULL` will use the default
+ value specified in `guacamole.properties` and a value of `0` denotes
+ unlimited. This only has an effect on `BALANCING` groups.
+
+`max_connections_per_user`
+: The maximum number of concurrent connections to allow to this connection
+ group at any one time *from a single user*. `NULL` will use the default
+ value specified in `guacamole.properties` and a value of `0` denotes
+ unlimited. This only has an effect on `BALANCING` groups.
+
+`enable_session_affinity`
+: Whether session affinity should apply to this connection group. If this
+ column is set to `TRUE` or `1`, users will be consistently routed to the
+ same underlying connection until they log out. The normal balancing
+ behavior will only apply for each user's first connection attempt during
+ any one Guacamole session. By default, session affinity is not enabled,
+ and connections will always be balanced across the entire connection
+ group. This only has an effect on `BALANCING` groups.
+
+Adding a connection group is even simpler than adding a new connection as there
+are no associated parameters stored in a separate table:
+
+```mysql
+-- Create connection group
+INSERT INTO guacamole_connection_group (connection_group_name, type)
+ VALUES ('test', 'ORGANIZATIONAL');
+```
+
+(jdbc-auth-schema-permissions)=
+
+### Permissions
+
+There are several permissions tables in the schema which correspond to the
+types of permissions in Guacamole's authentication model: system permissions,
+which control operations that affect the system as a whole, and permissions
+which control operations that affect specific objects within the system, such
+as users, connections, or groups.
+
+(jdbc-auth-schema-system-permissions)=
+
+#### System permissions
+
+System permissions are defined by entries in the `guacamole_system_permission`
+table. Each entry grants permission for a specific user or user group to
+perform a specific system operation.
+
+The `guacamole_system_permission` table contains the following columns:
+
+`entity_id`
+: The value of the `entity_id` column of the entry associated with the user
+ or user group owning this permission.
+
+`permission`
+: The permission being granted. This column can have one of six possible
+ values: `ADMINISTER`, which grants the ability to administer the entire
+ system (essentially a wildcard permission), `CREATE_CONNECTION`, which
+ grants the ability to create connections, `CREATE_CONNECTION_GROUP`, which
+ grants the ability to create connections groups, `CREATE_SHARING_PROFILE`,
+ which grants the ability to create sharing profiles, `CREATE_USER`, which
+ grants the ability to create users, or `CREATE_USER_GROUP`, which grants
+ the ability to create user groups.
+
+(jdbc-auth-schema-user-permissions)=
+
+#### User permissions
+
+User permissions are defined by entries in the `guacamole_user_permission`
+table. Each entry grants permission for a specific user or user group to
+perform a specific operation on an existing user.
+
+The `guacamole_user_permission` table contains the following columns:
+
+`entity_id`
+: The value of the `entity_id` column of the entry associated with the user
+ or user group owning this permission.
+
+`affected_user_id`
+: The value of the `user_id` column of the entry associated with the user
+ *affected* by this permission. This is the user that would be the object
+ of the operation represented by this permission.
+
+`permission`
+: The permission being granted. This column can have one of four possible
+ values: `ADMINISTER`, which grants the ability to add or remove
+ permissions which affect the user, `READ`, which grants the ability to
+ read data associated with the user, `UPDATE`, which grants the ability to
+ update data associated with the user, or `DELETE`, which grants the
+ ability to delete the user.
+
+(jdbc-auth-schema-group-permissions)=
+
+#### User group permissions
+
+User group permissions are defined by entries in the
+`guacamole_user_group_permission` table. Each entry grants permission for a
+specific user or user group to perform a specific operation on an existing user
+group.
+
+The `guacamole_user_group_permission` table contains the following columns:
+
+`entity_id`
+: The value of the `entity_id` column of the entry associated with the user
+ or user group owning this permission.
+
+`affected_user_group_id`
+: The value of the `user_group_id` column of the entry associated with the
+ user group *affected* by this permission. This is the user group that
+ would be the object of the operation represented by this permission.
+
+`permission`
+: The permission being granted. This column can have one of four possible
+ values: `ADMINISTER`, which grants the ability to add or remove
+ permissions which affect the user group, `READ`, which grants the ability
+ to read data associated with the user group, `UPDATE`, which grants the
+ ability to update data associated with the user group, or `DELETE`, which
+ grants the ability to delete the user group.
+
+(jdbc-auth-schema-connection-permissions)=
+
+#### Connection permissions
+
+Connection permissions are defined by entries in the
+`guacamole_connection_permission` table. Each entry grants permission for a
+specific user or user group to perform a specific operation on an existing
+connection.
+
+The `guacamole_connection_permission` table contains the following columns:
+
+`entity_id`
+: The value of the `entity_id` column of the entry associated with the user
+ or user group owning this permission.
+
+`connection_id`
+: The value of the `connection_id` column of the entry associated with the
+ connection affected by this permission. This is the connection that would
+ be the object of the operation represented by this permission.
+
+`permission`
+: The permission being granted. This column can have one of four possible
+ values: `ADMINISTER`, which grants the ability to add or remove
+ permissions which affect the connection, `READ`, which grants the ability
+ to read data associated with the connection (a prerequisite for
+ connecting), `UPDATE`, which grants the ability to update data associated
+ with the connection, or `DELETE`, which grants the ability to delete the
+ connection.
+
+(jdbc-auth-schema-sharing-profile-permissions)=
+
+#### Sharing profile permissions
+
+Sharing profile permissions are defined by entries in the
+`guacamole_sharing_profile_permission` table. Each entry grants permission for
+a specific user or user group to perform a specific operation on an existing
+sharing profile.
+
+The `guacamole_sharing_profile_permission` table contains the following
+columns:
+
+`entity_id`
+: The value of the `entity_id` column of the entry associated with the user
+ or user group owning this permission.
+
+`sharing_profile_id`
+: The value of the `sharing_profile_id` column of the entry associated with
+ the sharing profile affected by this permission. This is the sharing
+ profile that would be the object of the operation represented by this
+ permission.
+
+`permission`
+: The permission being granted. This column can have one of four possible
+ values: `ADMINISTER`, which grants the ability to add or remove
+ permissions which affect the sharing profile, `READ`, which grants the
+ ability to read data associated with the sharing profile (a prerequisite
+ for using the sharing profile to share an active connection), `UPDATE`,
+ which grants the ability to update data associated with the sharing
+ profile, or `DELETE`, which grants the ability to delete the sharing
+ profile.
+
+(jdbc-auth-schema-connection-group-permissions)=
+
+#### Connection group permissions
+
+Connection group permissions are defined by entries in the
+`guacamole_connection_group_permission` table. Each entry grants permission for
+a specific user or user group to perform a specific operation on an existing
+connection group.
+
+The `guacamole_connection_group_permission` table contains the following
+columns:
+
+`entity_id`
+: The value of the `entity_id` column of the entry associated with the user
+ or user group owning this permission.
+
+`connection_group_id`
+: The value of the `connection_group_id` column of the entry associated with
+ the connection group affected by this permission. This is the connection
+ group that would be the object of the operation represented by this
+ permission.
+
+`permission`
+: The permission being granted. This column can have one of four possible
+ values: `ADMINISTER`, which grants the ability to add or remove
+ permissions which affect the connection group, `READ`, which grants the
+ ability to read data associated with the connection group, `UPDATE`, which
+ grants the ability to update data associated with the connection group, or
+ `DELETE`, which grants the ability to delete the connection group (and
+ implicitly its contents).
+
diff --git a/src/ldap-auth.md b/src/ldap-auth.md
new file mode 100644
index 0000000..d991e1a
--- /dev/null
+++ b/src/ldap-auth.md
@@ -0,0 +1,561 @@
+LDAP authentication
+===================
+
+Guacamole supports LDAP authentication via an extension available from the main
+project website. This extension allows users and connections to be stored
+directly within an LDAP directory. If you have a centralized authentication
+system that uses LDAP, Guacamole's LDAP support can be a good way to allow your
+users to use their existing usernames and passwords to log into Guacamole.
+
+To use the LDAP authentication extension, you will need:
+
+1. An LDAP directory as storage for all authentication data, such as OpenLDAP.
+
+2. The ability to modify the schema of your LDAP directory.
+
+The instructions here assume you already have an LDAP directory installed and
+working, and do not cover the initial setup of such a directory.
+
+:::{important}
+This chapter involves modifying the contents of `GUACAMOLE_HOME` - the
+Guacamole configuration directory. If you are unsure where `GUACAMOLE_HOME` is
+located on your system, please consult [](configuring-guacamole) before
+proceeding.
+:::
+
+(ldap-architecture)=
+
+How Guacamole uses LDAP
+-----------------------
+
+If the LDAP extension is installed, Guacamole will authenticate users against
+your LDAP server by attempting a bind as that user. The given username and
+password will be submitted to the LDAP server during the bind attempt.
+
+If the bind attempt is successful, the set of available Guacamole connections
+is queried from the LDAP directory by executing an LDAP query as the bound
+user. Each Guacamole connection is represented within the directory as a
+special type of group: `guacConfigGroup`. Attributes associated with the group
+define the protocol and parameters of the connection, and users are allowed
+access to the connection only if they are associated with that group.
+
+This architecture has a number of benefits:
+
+1. Your users can use their existing usernames and passwords to log into
+ Guacamole.
+
+2. You can manage Guacamole connections using the same tool that you already
+ use to manage your LDAP directory, such as [Apache Directory
+ Studio](https://directory.apache.org/studio/).
+
+3. Existing security restrictions can limit visibility/accessibility of
+ Guacamole connections.
+
+4. Access to connections can easily be granted and revoked, as each connection
+ is represented by a group.
+
+:::{important}
+Though Guacamole connections can be stored within the LDAP directory, this is
+not required. Connection data can alternatively be stored within a database
+like MySQL or PostgreSQL as long as the LDAP username matches the username of
+the database user. Configuring Guacamole to use a database for authentication
+or connection storage is covered in [](jdbc-auth) and later in this chapter in
+[](ldap-and-database).
+:::
+
+(ldap-downloading)=
+
+Downloading the LDAP extension
+------------------------------
+
+The LDAP authentication extension is available separately from the main
+`guacamole.war`. The link for this and all other officially-supported and
+compatible extensions for a particular version of Guacamole are provided on the
+release notes for that version. You can find the release notes for current
+versions of Guacamole here: <http://guacamole.apache.org/releases/>.
+
+The LDAP authentication extension is packaged as a `.tar.gz` file containing:
+
+`guacamole-auth-ldap-1.3.0.jar`
+: The Guacamole LDAP support extension itself, which must be placed in
+ `GUACAMOLE_HOME/extensions`.
+
+`schema/`
+: LDAP schema files. An `.ldif` file compatible with OpenLDAP is provided, as
+ well as a `.schema` file compliant with RFC-2252. The `.schema` file can be
+ transformed into the `.ldif` file automatically.
+
+(ldap-schema-changes)=
+
+Preparing your LDAP directory (optional)
+----------------------------------------
+
+Although your LDAP directory already provides a means of storing and
+authenticating users, Guacamole also needs storage of connection configuration
+data, such as hostnames and ports, and a means of associating users with
+connections that they should have access to. You can do this either through
+modifying the LDAP directory schema, or through using a database like MySQL or
+PostgreSQL. If you do not wish to use the LDAP directory for connection
+storage, skip ahead to [](ldap-and-database).
+
+If you wish to store connection data directly within the LDAP directory, the
+required modifications to the LDAP schema are made through applying one of the
+provided schema files. These schema files define an additional object class,
+`guacConfigGroup`, which contains all configuration information for a
+particular connection, and can be associated with arbitrarily-many users and
+groups. Each connection defined by a `guacConfigGroup` will be accessible only
+by users who are members of that group (specified with the member attribute),
+or who are members of associated groups (specified with the `seeAlso`
+attribute).
+
+:::{important}
+The instructions given for applying the Guacamole LDAP schema changes are
+specific to OpenLDAP, but other LDAP implementations, including Active
+Directory, will have their own methods for updating the schema.
+
+If you are not using OpenLDAP, a standards-compliant schema file is provided
+that can be used to update the schema of any LDAP directory supporting
+RFC-2252. Please consult the documentation of your LDAP directory to determine
+how such schema changes can be applied.
+:::
+
+The schema files are located within the `schema/` directory of the archive
+containing the LDAP extension. You will only need one of these files:
+
+`guacConfigGroup.schema`
+: A standards-compliant file describing the schema. This file can be used with
+ any LDAP directory compliant with RFC-2252.
+
+`guacConfigGroup.ldif`
+: An LDIF file compatible with OpenLDAP. This file was automatically built from
+ the provided `.schema` file for convenience.
+
+This chapter will cover applying `guacConfigGroup.ldif` to an OpenLDAP server.
+If you are not using OpenLDAP, your LDAP server should provide documentation
+for modifying its schema. If this is the case, please consult the documentation
+of your LDAP server before proceeding.
+
+### Applying the schema changes to OpenLDAP
+
+Schema changes to OpenLDAP are applied using the {command}`ldapadd` utility
+with the provided `guacConfigGroup.ldif` file:
+
+```console
+# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f schema/guacConfigGroup.ldif
+adding new entry "cn=guacConfigGroup,cn=schema,cn=config"
+
+#
+```
+
+If the `guacConfigGroup` object was added successfully, you should see output
+as above. You can confirm the presence of the new object class using
+{command}`ldapsearch`:
+
+```console
+# ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config dn
+dn: cn=schema,cn=config
+
+dn: cn={0}core,cn=schema,cn=config
+
+dn: cn={1}cosine,cn=schema,cn=config
+
+dn: cn={2}nis,cn=schema,cn=config
+
+dn: cn={3}inetorgperson,cn=schema,cn=config
+
+dn: cn={4}guacConfigGroup,cn=schema,cn=config
+
+#
+```
+
+(ldap-and-database)=
+
+Associating LDAP with a database
+--------------------------------
+
+If you install both the LDAP authentication as well as support for a database
+(following the instructions in [](jdbc-auth)), Guacamole will automatically
+attempt to authenticate against both systems whenever a user attempts to log
+in. In addition to any visible objects within the LDAP directory, that user
+will have access to any data associated with their account in the database, as
+well as any data associated with user groups that they belong to. LDAP user
+accounts and groups will be considered equivalent to database users and groups
+if their unique names are identical, as determined by the attributes given for
+[the `ldap-username-attribute` and `ldap-group-name-attribute`
+properties](guac-ldap-config).
+
+Data can be manually associated with LDAP user accounts or groups by creating
+corresponding users or groups within the database which each have the same
+names. As long as the names are identical, a successful login attempt against
+LDAP will be trusted by the database authentication, and that user's associated
+data will be visible.
+
+If an administrator account (such as the default `guacadmin` user provided with
+the database authentication) has a corresponding user in the LDAP directory
+with permission to read other LDAP users and groups, the Guacamole
+administrative interface will include them in the lists presented to the
+administrator, and will allow connections from the database to be associated
+with those users or groups directly.
+
+(installing-ldap-auth)=
+
+Installing LDAP authentication
+------------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located within
+the `GUACAMOLE_HOME/extensions` directory. To install the LDAP authentication
+extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+ exist.
+
+2. Copy `guacamole-auth-ldap-1.3.0.jar` within `GUACAMOLE_HOME/extensions`.
+
+3. Configure Guacamole to use LDAP authentication, as described below.
+
+:::{important}
+You will need to restart Guacamole by restarting your servlet container in
+order to complete the installation. Doing this will disconnect all active
+users, so be sure that it is safe to do so prior to attempting installation. If
+you do not configure the LDAP authentication properly, Guacamole will not start
+up again until the configuration is fixed.
+:::
+
+(guac-ldap-config)=
+
+### Configuring Guacamole for LDAP
+
+Additional properties may be added to `guacamole.properties` to describe how
+your LDAP directory is organized and how Guacamole should connect (and bind) to
+your LDAP server. Among these properties, only the ldap-user-base-dn property
+is required:
+
+`ldap-hostname`
+: The hostname of your LDAP server. If omitted, "localhost" will be used by
+ default. You will need to use a different value if your LDAP server is
+ located elsewhere.
+
+`ldap-port`
+: The port your LDAP server listens on. If omitted, the standard LDAP or LDAPS
+ port will be used, depending on the encryption method specified with
+ `ldap-encryption-method` (if any). Unencrypted LDAP uses the standard port of
+ 389, while LDAPS uses port 636. Unless you manually configured your LDAP
+ server to do otherwise, your LDAP server probably listens on port 389.
+
+`ldap-encryption-method`
+: The encryption mechanism that Guacamole should use when communicating with
+ your LDAP server. Legal values are "none" for unencrypted LDAP, "ssl" for
+ LDAP over SSL/TLS (commonly known as LDAPS), or "starttls" for STARTTLS. If
+ omitted, encryption will not be used.
+
+ If you do use encryption when connecting to your LDAP server, you will need
+ to ensure that its certificate chain can be verified using the certificates
+ in Java's trust store, often referred to as `cacerts`. If this is not the
+ case, you will need to use Java's `keytool` utility to either add the
+ necessary certificates or to create a new trust store containing those
+ certificates.
+
+ If you will be using your own trust store and not the default `cacerts`, you
+ will need to specify the full path to that trust store using the system
+ property `javax.net.ssl.trustStore`. Note that this is a system property and
+ *not* a Guacamole property; it must be specified when starting the JVM using
+ the `-D` option. Your servlet container will provide some means of specifying
+ startup options for the JVM.
+
+`ldap-max-search-results`
+: The maximum number of search results that can be returned by a single LDAP
+ query. LDAP queries which exceed this maximum will fail. *This property is
+ optional.* If omitted, each LDAP query will be limited to a maximum of 1000
+ results.
+
+`ldap-search-bind-dn`
+: The DN (Distinguished Name) of the user to bind as when authenticating users
+ that are attempting to log in. If specified, Guacamole will query the LDAP
+ directory to determine the DN of each user that logs in. If omitted, each
+ user's DN will be derived directly using the base DN specified with
+ `ldap-user-base-dn`.
+
+`ldap-search-bind-password`
+: The password to provide to the LDAP server when binding as
+ `ldap-search-bind-dn` to authenticate other users. This property is only used
+ if ldap-search-bind-dn is specified. If omitted, but `ldap-search-bind-dn` is
+ specified, Guacamole will attempt to bind with the LDAP server without a
+ password.
+
+`ldap-user-base-dn`
+: The base of the DN for all Guacamole users. *This property is absolutely
+ required in all cases.* All Guacamole users must be descendents of this base
+ DN.
+
+ If a search DN is provided (via `ldap-search-bind-dn`), then Guacamole users
+ need only be somewhere within the subtree of the specified user base DN.
+
+ If a search DN *is not* provided, then all Guacamole users must be *direct
+ descendents* of this base DN, as the base DN will be appended to the username
+ to derive the user's DN. For example, if `ldap-user-base-dn` is
+ "`ou=people,dc=example,dc=net`", and `ldap-username-attribute` is "uid", then
+ a person attempting to login as "`user`" would be mapped to the following
+ full DN: "`uid=user,ou=people,dc=example,dc=net`".
+
+`ldap-username-attribute`
+: The attribute or attributes which contain the username within all Guacamole
+ user objects in the LDAP directory. Usually, and by default, this will simply
+ be "uid". If your LDAP directory contains users whose usernames are dictated
+ by different attributes, multiple attributes can be specified here, separated
+ by commas, but beware: *doing so requires that a search DN be provided with
+ `ldap-search-bind-dn`*.
+
+ If a search DN *is not* provided, then the single username attribute
+ specified here will be used together with the user base DN to directly derive
+ the full DN of each user. For example, if `ldap-user-base-dn` is
+ "`ou=people,dc=example,dc=net`", and `ldap-username-attribute` is "uid", then
+ a person attempting to login as "`user`" would be mapped to the following
+ full DN: "`uid=user,ou=people,dc=example,dc=net`".
+
+`ldap-member-attribute`
+: The attribute which contains the members within all group objects in the LDAP
+ directory. Usually, and by default, this will simply be "member". If your
+ LDAP directory contains groups whose members are dictated by a different
+ attribute, it can be specified here.
+
+`ldap-member-attribute-type`
+: Specify whether the attribute defined in `ldap-member-attribute` (Usually
+ "member") identifies a group member by DN or by usercode. Possible values:
+ "dn" (the default, if not specified) or "uid".
+
+ Example: an LDAP server may present groups using the `groupOfNames`
+ scheme:
+
+ ```
+ dn: cn=group1,ou=Groups,dc=example,dc=net
+ objectClass: groupOfNames
+ cn: group1
+ gidNumber: 12345
+ member: user1,ou=People,dc=example,dc=net
+ member: user2,ou=People,dc=example,dc=net
+ ```
+
+ `ldap-member-attribute` is `member` and `ldap-member-attribute-type` is `dn`.
+
+ Example: an LDAP server may present groups using the `posixGroup`
+ scheme:
+
+ ```
+ dn: cn=group1,ou=Groups,dc=example,dc=net
+ objectClass: posixGroup
+ cn: group1
+ gidNumber: 12345
+ memberUid: user1
+ memberUid: user2
+ ```
+
+ `ldap-member-attribute` is `memberUid` and `ldap-member-attribute-type` is
+ `uid`
+
+`ldap-user-attributes`
+: The attribute or attributes to retrieve from the LDAP directory for the
+ currently logged-in user, separated by commas. If specified, the attributes
+ listed here are retrieved from each authenticated user and dynamically
+ applied to the parameters of that user's connections as [parameter
+ tokens](parameter-tokens) with the prefix "`LDAP_`".
+
+ When a user authenticates with LDAP and accesses a particular Guacamole
+ connection, the values of these tokens will be the values of their
+ corresponding attributes at the time of authentication. If the attribute has
+ no value for the current user, then the corresponding token is not applied.
+ If the attribute has multiple values, then the first value of the attribute
+ is used.
+
+ When converting an LDAP attribute name into a parameter token name, the name
+ of the attribute is transformed into uppercase with each word separated by
+ underscores, a naming convention referred to as "uppercase with underscores"
+ or "[screaming snake case](https://en.wikipedia.org/wiki/Naming_convention_(programming)#Multiple-word_identifiers)".
+
+ For example:
+
+ | LDAP Attribute | Parameter Token |
+ | ---------------------------------- | ---------------------------------------------- |
+ | `lowercase-with-dashes` | `${LDAP_LOWERCASE_WITH_DASHES}` |
+ | `CamelCase` | `${LDAP_CAMEL_CASE}` |
+ | `headlessCamelCase` | `${LDAP_HEADLESS_CAMEL_CASE}` |
+ | `lettersAndNumbers1234` | `${LDAP_LETTERS_AND_NUMBERS_1234}` |
+ | `aRANDOM_mixOf-3NAMINGConventions` | `${LDAP_A_RANDOM_MIX_OF_3_NAMING_CONVENTIONS}` |
+
+ Usage of parameter tokens is discussed in more detail in
+ [](configuring-guacamole) in [](parameter-tokens).
+
+`ldap-user-search-filter`
+: The search filter used to query the LDAP tree for users that can log into and
+ be granted privileges in Guacamole. *If this property is omitted the default of
+ `(objectClass=*)` will be used.*
+
+`ldap-config-base-dn`
+: The base of the DN for all Guacamole configurations. *This property is
+ optional.* If omitted, the configurations of Guacamole connections will
+ simply not be queried from the LDAP directory. If specified, this base DN
+ will be used when querying the configurations accessible by a user once they
+ have successfully logged in.
+
+ Each configuration is analogous to a connection. Within Guacamole's LDAP
+ support, each configuration functions as a group, having user members (via
+ the `member` attribute) and optionally group members (via the `seeAlso`
+ attribute), where each member of a particular configuration group will have
+ access to the connection defined by that configuration.
+
+`ldap-group-base-dn`
+: The base of the DN for all user groups that may be used by other extensions
+ to define permissions or that may referenced within Guacamole configurations
+ using the standard seeAlso attribute. All groups which will be used to
+ control access to Guacamole configurations must be descendents of this base
+ DN. *If this property is omitted, the `seeAlso` attribute will have no effect
+ on Guacamole configurations.*
+
+`ldap-group-name-attribute`
+: The attribute or attributes which define the unique name of user groups in
+ the LDAP directory. Usually, and by default, this will simply be "cn". If
+ your LDAP directory contains groups whose names are dictated by different
+ attributes, multiple attributes can be specified here, separated by commas.
+
+`ldap-dereference-aliases`
+: Controls whether or not the LDAP connection follows (dereferences) aliases as
+ it searches the tree. Possible values for this property are "never" (the
+ default) so that aliases will never be followed, "searching" to dereference
+ during search operations after the base object is located, "finding" to
+ dereference in order to locate the search base, but not during the actual
+ search, and "always" to always dereference aliases.
+
+`ldap-follow-referrals`
+: This option controls whether or not the LDAP module follow referrals when
+ processing search results from a LDAP search. Referrals can be pointers to
+ other parts of an LDAP tree, or to a different server/connection altogether.
+ This is a boolean parameter, with valid options of "true" or "false." The
+ default is false. When disabled, LDAP referrals will be ignored when
+ encountered by the Guacamole LDAP client and the client will move on to the
+ next result. When enabled, the LDAP client will follow the referral and
+ process results within the referral, subject to the maximum hops parameter
+ below.
+
+`ldap-max-referral-hops`
+: This option controls the maximum number of referrals that will be processed
+ before the LDAP client refuses to follow any more referrals. The default is
+ 5. If the `ldap-follow-referrals` property is set to false (the default),
+ this option has no effect. If the `ldap-follow-referrals` option is set
+ to true, this will limit the depth of referrals followed to the number
+ specified.
+
+`ldap-operation-timeout`
+: This option sets the timeout, in seconds, of any single LDAP operation. The
+ default is 30 seconds. When this timeout is reached LDAP operations will be
+ aborted.
+
+Again, even if the defaults are sufficient for the other properties, *you must
+still specify the `ldap-user-base-dn` property*. An absolutely minimal
+configuration for LDAP authentication will look like the following:
+
+```
+# LDAP properties
+ldap-user-base-dn: ou=people,dc=example,dc=net
+```
+
+### Completing the installation
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before the LDAP authentication will take effect. Restart your servlet container
+and give the new authentication a try.
+
+:::{important}
+You only need to restart your servlet container. *You do not need to restart
+guacd*.
+
+guacd is completely independent of the web application and does not deal with
+`guacamole.properties` or the authentication system in any way. Since you are
+already restarting the servlet container, restarting guacd as well technically
+won't hurt anything, but doing so is completely pointless.
+:::
+
+If Guacamole does not come back online after restarting your servlet container,
+check the logs. Problems in the configuration of the LDAP extension will
+prevent Guacamole from starting up, and any such errors will be recorded in the
+logs of your servlet container. If properly configured, you will be able to log
+in as any user within the defined ldap-user-base-dn.
+
+(ldap-auth-schema)=
+
+The LDAP schema
+---------------
+
+Guacamole's LDAP support allows users and connections to be managed purely
+within an LDAP directory defined in `guacamole.properties`. This is
+accomplished with a minimum of changes to the standard LDAP schema - all
+Guacamole users are traditional LDAP users and share the same mechanism of
+authentication. The only new type of object required is a representation for
+Guacamole connections, `guacConfigGroup`, which was added to your server's
+schema during the install process above.
+
+### Users
+
+All Guacamole users, as far as the LDAP support is concerned, are LDAP users
+with standard LDAP credentials. When a user signs in to Guacamole, their
+username and password will be used to bind to the LDAP server. If this bind
+operation is successful, the available connections are queried from the
+directory and the user is allowed in.
+
+### Connections and parameters
+
+Each connection is represented by an instance of the `guacConfigGroup` object
+class, an extended version of the standard LDAP `groupOfNames`, which provides
+a protocol and set of parameters. Only members of the `guacConfigGroup` will
+have access to the corresponding connection.
+
+The `guacConfigGroup` object class provides two new attributes in addition to
+those provided by `groupOfNames`:
+
+`guacConfigProtocol`
+: The protocol associated with the connection, such as "`vnc`" or "`rdp`". This
+ attribute is required for every `guacConfigGroup` and can be given only once.
+
+`guacConfigParameter`
+: The name and value of a parameter for the specified protocol. This is given
+ as `name=value`, where "name" is the name of the parameter, as defined by the
+ documentation for the protocol specified, and "value" is any allowed value for
+ that parameter.
+
+ This attribute can be given multiple times for the same connection.
+
+For example, to create a new VNC connection which connects to "localhost" at
+port 5900, while granting access to `user1` and `user2`, you could create an
+`.ldif` file like the following:
+
+```
+dn: cn=Example Connection,ou=groups,dc=example,dc=net
+objectClass: guacConfigGroup
+objectClass: groupOfNames
+cn: Example Connection
+guacConfigProtocol: vnc
+guacConfigParameter: hostname=localhost
+guacConfigParameter: port=5900
+guacConfigParameter: password=secret
+member: cn=user1,ou=people,dc=example,dc=net
+member: cn=user2,ou=people,dc=example,dc=net
+```
+
+The new connection can then be created using the {command}`ldapadd` utility:
+
+```console
+$ ldapadd -x -D cn=admin,dc=example,dc=net -W -f example-connection.ldif
+Enter LDAP Password:
+adding new entry "cn=Example Connection,ou=groups,dc=example,dc=net"
+
+$
+```
+
+Where `cn=admin,dc=example,dc=net` is an administrator account with permission
+to create new entries, and `example-connection.ldif` is the name of the `.ldif`
+file you just created.
+
+There is, of course, no need to use only the standard LDAP utilities to create
+connections and users. There are useful graphical environments for manipulating
+LDAP directories, such as [Apache Directory Studio](https://directory.apache.org/studio/),
+which make many of the tasks given above much easier.
+
diff --git a/src/libguac.md b/src/libguac.md
new file mode 100644
index 0000000..d593639
--- /dev/null
+++ b/src/libguac.md
@@ -0,0 +1,411 @@
+libguac
+=======
+
+The C API for extending and developing with Guacamole is libguac. All native
+components produced by the Guacamole project link with this library, and this
+library provides the common basis for extending the native functionality of
+those native components (by implementing client plugins).
+
+libguac is used mainly for developing client plugins like libguac-client-vnc or
+libguac-client-rdp, or for developing a proxy supporting the Guacamole protocol
+like guacd. This chapter is intended to give an overview of how libguac is
+used, and how to use it for general communication with the Guacamole protocol.
+
+(libguac-error-handling)=
+
+Error handling
+--------------
+
+Most functions within libguac handle errors by returning a zero or non-zero
+value, whichever is appropriate for the function at hand. If an error is
+encountered, the `guac_error` variable is set appropriately, and
+`guac_error_message` contains a statically-allocated human-readable string
+describing the context of the error. These variables intentionally mimic the
+functionality provided by `errno` and `errno.h`.
+
+Both `guac_error` and `guac_error_message` are defined within `error.h`. A
+human-readable string describing the error indicated by `guac_error` can be
+retrieved using `guac_status_string()`, which is also statically allocated.
+
+If functions defined within client plugins set `guac_error` and
+`guac_error_message` appropriately when errors are encountered, the messages
+logged to syslog by guacd will be more meaningful for both users and
+developers.
+
+(libguac-client-plugins)=
+
+Client plugins
+--------------
+
+Client plugins are libraries which follow specific conventions such that they
+can be loaded dynamically by guacd. All client plugins *must*:
+
+1. Follow a naming convention, where the name of the library is
+ {samp}`libguac-client-{PROTOCOL}`. *This is necessary for guacd to locate
+ the library for a requested protocol.*
+
+2. Be linked against libguac, the library used by guacd to handle the Guacamole
+ protocol. The structures which are given to functions invoked by guacd are
+ defined by libguac, and are expected to be manipulated via the functions
+ provided by libguac or as otherwise documented within the structure itself.
+ *Communication between guacd and client plugins is only possible if they
+ share the same core structural and functional definitions provided by
+ libguac.*
+
+3. Implement the standard entry point for client plugins, `guac_client_init()`,
+ described in more detail below. It is this function which initializes the
+ structures provided by guacd such that users can join and interact with the
+ connection.
+
+(libguac-lifecycle-entry)=
+
+### Entry point
+
+All client plugins must provide a function named `guac_client_init` which
+accepts, as its sole argument, a pointer to a `guac_client` structure. This
+function is similar in principle to the main() function of a C program, and it
+is the responsibility of this function to initialize the provided structure as
+necessary to begin the actual remote desktop connection, allow users to
+join/leave, etc.
+
+The provided `guac_client` will already have been initialized with handlers for
+logging, the broadcast socket, etc. The absolutely critical pieces which must
+be provided by `guac_client_init` are:
+
+1. A handler for users which join the connection (`join_handler`). The join
+ handler is also usually the most appropriate place for the actual remote
+ desktop connection to be established.
+
+2. A `NULL`-terminated set of argument names which the client plugin accepts,
+ assigned to the args property of the given `guac_client`. As the handshake
+ procedure is completed for each connecting user, these argument names will
+ be presented as part of the handshake, and the values for those arguments
+ will be passed to the join handler once the handshake completes.
+
+3. A handler for users leaving the connection (`leave_handler`), if any
+ cleanup, updates, etc. are required.
+
+4. A handler for freeing the data associated with the `guac_client` after the
+ connection has terminated (`free_handler`). If your plugin will allocate any
+ data at all, implementing the free handler is necessary to avoid memory leaks.
+
+If `guac_client_init` returns successfully, guacd will proceed with allowing
+the first use to join the connection, and the rest of the plugin lifecycle
+commences.
+
+(libguac-lifecycle-users)=
+
+### Joining/leaving a connection
+
+Whenever a user joins a connection, including the very first user of a
+connection (the user which is establishing the remote desktop connection in the
+first place), the join handler of the `guac_client` will be invoked. This
+handler is provided with the `guac_user` structure representing the user that
+just joined, along with the arguments provided during the handshake procedure:
+
+```c
+int join_handler(guac_user* user, int argc, char** argv) {
+ /* Synchronize display state, init the user, etc. */
+}
+
+...
+
+/* Within guac_client_init */
+client->join_handler = join_handler;
+```
+
+As the parameters and user information provided during the Guacamole protocol
+handshake are often required to be known before the remote desktop connection
+can be established, the join handler is usually the best place to create a
+thread which establishes the remote desktop connection and updates the display
+accordingly.
+
+If necessary, the user which first established the connection can be
+distinguished from all other users by the owner flag of `guac_user`, which will
+be set to a non-zero value.
+
+Once a user has disconnected, the leave handler of `guac_client` will be
+invoked. Just as with the join handler, this handler is provided the
+`guac_user` structure of the user that disconnected. The `guac_user` structure
+will be freed immediately after the handler completes:
+
+```c
+int leave_handler(guac_user* user) {
+ /* Free user-specific data and clean up */
+}
+
+...
+
+/* Within guac_client_init */
+client->leave_handler = leave_handler;
+```
+
+(libguac-lifecycle-termination)=
+
+### Termination
+
+Once the last user of a connection has left, guacd will begin freeing resources
+allocated to that connection, invoking the free handler of the `guac_client`.
+At this point, the "leave" handler has been invoked for all previous users. All
+that remains is for the client plugin to free any remaining data that it
+allocated, such that guacd can clean up the rest:
+
+```c
+int free_handler(guac_client* client) {
+ /* Disconnect, free client-specific data, etc. */
+}
+
+...
+
+/* Within guac_client_init */
+client->free_handler = free_handler;
+```
+
+(libguac-layers)=
+
+Layers and buffers
+------------------
+
+The main operand of all drawing instructions is the layer, represented within
+libguac by the `guac_layer` structure. Each `guac_layer` is normally allocated
+using `guac_client_alloc_layer()` or `guac_client_alloc_buffer()`, depending on
+whether a layer or buffer is desired, and freed with `guac_client_free_layer()`
+or `guac_client_free_buffer()`.
+
+:::{important}
+Care must be taken to invoke the allocate and free pairs of each type of layer
+correctly. `guac_client_free_layer()` should only be used to free layers
+allocated with `guac_client_alloc_layer()`, and `guac_client_free_buffer()`
+should only be used to free layers allocated with `guac_client_alloc_buffer()`,
+all called using the same instance of `guac_client`.
+
+If these restrictions are not observed, the effect of invoking these functions
+is undefined.
+:::
+
+Using these layer management functions allows you to reuse existing layers or
+buffers after their original purpose has expired, thus conserving resources on
+the client side, as allocation of new layers within the remote client is a
+relatively expensive operation.
+
+It is through layers and buffers that Guacamole provides support for
+hardware-accelerated compositing and cached updates. Creative use of layers and
+buffers leads to efficient updates on the client side, which usually translates
+into speed and responsiveness.
+
+Regardless of whether you allocate new layers or buffers, there is always one
+layer guaranteed to be present: the default layer, represented by libguac as
+`GUAC_DEFAULT_LAYER`. If you only wish to affect the main display of the
+connected client somehow, this is the layer you want to use as the operand of
+your drawing instruction.
+
+(libguac-streams)=
+
+Streams
+-------
+
+In addition to drawing, the Guacamole protocol supports streaming of arbitrary
+data. The main operand of all streaming instructions is the stream, represented
+within libguac by the `guac_stream` structure. Each `guac_stream` exists
+either at the user or client levels, depending on whether the stream is
+intended to be broadcast to all users or just one, and is thus allocated using
+either `guac_client_alloc_stream()` or `guac_user_alloc_stream()`.
+Explicitly-allocated streams must eventually be freed with
+`guac_client_free_stream()` or `guac_user_free_stream()`.
+
+:::{important}
+Just as with layers, care must be taken to invoke the allocate and free pairs
+correctly for each explicitly-allocated stream. `guac_client_free_stream()`
+should only be used to free streams allocated with
+`guac_client_alloc_stream()`, and `guac_user_free_stream()` should only be used
+to free streams allocated with `guac_user_alloc_stream()`.
+
+If these restrictions are not observed, the effect of invoking these functions
+is undefined.
+:::
+
+Streams are the means by which data is transmitted for clipboard (via the
+["clipboard" instruction](clipboard-instruction)), audio (via the ["audio"
+instruction](audio-instruction)), and even the images which make up typical
+drawing operations (via the ["img" instruction](img-instruction)). They will
+either be allocated for you, when an inbound stream is received from a user, or
+allocated manually, when an outbound stream needs to be sent to a user. As with
+`guac_client` and `guac_user`, each `guac_stream` has a set of handlers which
+correspond to instructions received related to streams. These instructions are
+documented in more detail in [](guacamole-protocol-streaming) and
+[](protocol-reference).
+
+(libguac-sending-instructions)=
+
+Sending instructions
+--------------------
+
+All drawing in Guacamole is accomplished through the sending of instructions to
+the connected client using the Guacamole protocol. The same goes for streaming
+audio, video, or file content. All features and content supported by Guacamole
+ultimately reduce to one or more instructions which are part of the documented
+protocol.
+
+Most drawing using libguac is done using Cairo functions on a `cairo_surface_t`
+(see the Cairo API documentation) which is later streamed to the client using
+an img instruction and subsequent blob instructions, sent via
+`guac_client_stream_png()`. Cairo was chosen as a dependency of libguac to
+provide developers an existing and stable means of drawing to image buffers
+which will ultimately be sent as easy-to-digest PNG images.
+
+The Guacamole protocol also supports drawing primitives similar to those
+present in the Cairo API and HTML5's canvas tag. These instructions are
+documented individually in the Guacamole Protocol Reference in a section
+dedicated to drawing instructions, and like all Guacamole protocol
+instructions, each instruction has a corresponding function in libguac
+following the naming convention {samp}`guac_protocol_send_{OPCODE}()`.
+
+Each protocol function takes a `guac_socket` as an argument, which is the
+buffered I/O object used by libguac. For each active connection, there are two
+important types of `guac_socket` instance: the broadcast socket, which exists
+at the client level within the `guac_client`, and the per-user socket, which is
+accessible within each `guac_user`. Data sent along the client-level broadcast
+socket will be sent to all connected users beneath that `guac_client`, while
+data sent along a user-level socket will be sent only to that user.
+
+For example, to send a "size" instruction to all connected users via the
+client-level broadcast socket, you could invoke:
+
+```c
+guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, 1024, 768);
+```
+
+Or, if the instruction is only relevant to a particular user, the socket
+associated with that user can be used instead:
+
+```c
+guac_protocol_send_size(user->socket, GUAC_DEFAULT_LAYER, 1024, 768);
+```
+
+The sockets provided by libguac are threadsafe at the protocol level.
+Instructions written to a socket by multiple threads are guaranteed to be
+written atomically with respect to that socket.
+
+(libguac-event-handling)=
+
+Event handling
+--------------
+
+Generally, as guacd receives instructions from the connected client, it invokes
+event handlers if set within the associated `guac_user` or `guac_client`,
+depending on the nature of the event. Most events are user-specific, and thus
+the event handlers reside within the `guac_user` structure, but there are
+client-specific events as well, such as a user joining or leaving the current
+connection. Event handlers typically correspond to Guacamole protocol
+instructions received over the socket by a connected user, which in turn
+correspond to events which occur on the client side.
+
+(libguac-key-events)=
+
+### Key events
+
+When keys are pressed or released on the client side, the client sends key
+instructions to the server. These instructions are parsed and handled by
+calling the key event handler installed in the `key_handler` member of the
+`guac_user`. This key handler is given the keysym of the key that was changed,
+and a boolean value indicating whether the key was pressed or released.
+
+```c
+int key_handler(guac_user* user, int keysym, int pressed) {
+ /* Do something */
+}
+
+...
+
+/* Within the "join" handler of guac_client */
+user->key_handler = key_handler;
+```
+
+(libguac-mouse-events)=
+
+### Mouse events
+
+When the mouse is moved, and buttons are pressed or released, the client sends
+mouse instructions to the server. These instructions are parsed and handled by
+calling the mouse event handler installed in the `mouse_handler` member of the
+`guac_user`. This mouse handler is given the current X and Y coordinates of the
+mouse pointer, as well as a mask indicating which buttons are pressed and which
+are released.
+
+```c
+int mouse_handler(guac_user* user, int x, int y, int button_mask) {
+ /* Do something */
+}
+
+...
+
+/* Within the "join" handler of guac_client */
+user->mouse_handler = mouse_handler;
+```
+
+The file `client.h` also defines the mask of each button for convenience:
+
+`GUAC_CLIENT_MOUSE_LEFT`
+: The left mouse button, set when pressed.
+
+`GUAC_CLIENT_MOUSE_MIDDLE`
+: The middle mouse button, set when pressed.
+
+`GUAC_CLIENT_MOUSE_RIGHT`
+: The right mouse button, set when pressed.
+
+`GUAC_CLIENT_MOUSE_UP`
+: The button corresponding to one scroll in the upwards direction of the mouse
+ scroll wheel, set when scrolled.
+
+`GUAC_CLIENT_MOUSE_DOWN`
+: The button corresponding to one scroll in the downwards direction of the
+ mouse scroll wheel, set when scrolled.
+
+(libguac-clipboard-events)=
+
+### Clipboard, file, and other stream events
+
+If a connected user sends data which should be sent to the clipboard of the
+remote desktop, guacd will trigger the clipboard handler installed in the
+`clipboard_handler` member of the `guac_user` associated with that user.
+
+```c
+int clipboard_handler(guac_user* user, guac_stream* stream, char* mimetype) {
+ /* Do something */
+}
+
+...
+
+/* Within the "join" handler of guac_client */
+user->clipboard_handler = clipboard_handler;
+```
+
+The handler is expected to assign further handlers to the provided
+`guac_stream` as necessary, such that the ["blob"](blob-instruction) and
+["end"](end-instruction) instructions received along the stream can be handled.
+A similar handler is provided for received files:
+
+```c
+int file_handler(guac_user* user, guac_stream* stream,
+ char* mimetype, char* filename) {
+ /* Do something */
+}
+
+...
+
+/* Within the "join" handler of guac_client */
+user->file_handler = file_handler;
+```
+
+This pattern continues for all other types of streams which can be received
+from a user. The instruction which begins the stream has a corresponding
+handler within `guac_user`, and the metadata describing that stream and
+provided with the instruction is included within the parameters passed to that
+handler.
+
+These handlers are, of course, optional. If any type of stream lacks a
+corresponding handler, guacd will automatically close the stream and respond
+with an ["ack" instruction](ack-instruction) and appropriate error code,
+informing the user's Guacamole client that the stream is unsupported.
+
diff --git a/src/openid-auth.md b/src/openid-auth.md
new file mode 100644
index 0000000..9f03e32
--- /dev/null
+++ b/src/openid-auth.md
@@ -0,0 +1,160 @@
+OpenID Connect Authentication
+=============================
+
+[OpenID Connect](http://openid.net/connect/) is a widely-adopted open standard
+for implementing single sign-on (SSO). [Not to be confused with
+OAuth](https://oauth.net/articles/authentication/), which is *not* an
+authentication protocol, OpenID Connect defines an authentication protocol in
+the form of a simple identity layer on top of OAuth 2.0.
+
+Guacamole's OpenID Connect support implements the "[implicit
+flow](https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth)"
+of the OpenID Connect standard, and allows authentication of Guacamole users to
+be delegated to an identity provider which implements OpenID Connect, removing
+the need for users to log into Guacamole directly. This module must be layered
+on top of other authentication extensions that provide connection information,
+such as the [database authentication extension](jdbc-auth), as it only provides
+user authentication.
+
+(openid-downloading)=
+
+Downloading the OpenID Connect authentication extension
+-------------------------------------------------------
+
+The OpenID Connect authentication extension is available separately from the
+main `guacamole.war`. The link for this and all other officially-supported and
+compatible extensions for a particular version of Guacamole are provided on the
+release notes for that version. You can find the release notes for current
+versions of Guacamole here: <http://guacamole.apache.org/releases/>.
+
+The OpenID Connect authentication extension is packaged as a `.tar.gz` file
+containing only the extension itself, `guacamole-auth-openid-1.3.0.jar`, which
+must ultimately be placed in
+`GUACAMOLE_HOME/extensions`.
+
+(installing-openid-auth)=
+
+Installing support for OpenID Connect
+-------------------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located within
+the `GUACAMOLE_HOME/extensions` directory. *If you are unsure where
+`GUACAMOLE_HOME` is located on your system, please consult
+[](configuring-guacamole) before proceeding.*
+
+To install the OpenID Connect authentication extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+ exist.
+
+2. Copy `guacamole-auth-openid-1.3.0.jar` within `GUACAMOLE_HOME/extensions`.
+
+3. Configure Guacamole to use OpenID Connect authentication, as described
+ below.
+
+(guac-openid-config)=
+
+### Configuring Guacamole for single sign-on with OpenID Connect
+
+Guacamole's OpenID connect support requires several properties which describe
+both the identity provider and the Guacamole deployment. These properties are
+*absolutely required in all cases*, as they dictate how Guacamole should
+connect to the identity provider, how it should verify the identity provider's
+response, and how the identity provider should redirect users back to Guacamole
+once their identity has been confirmed:
+
+`openid-authorization-endpoint`
+: The authorization endpoint (URI) of the OpenID service.
+
+ This value should be provided to you by the identity provider. For identity
+ providers that implement [OpenID Connect
+ Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html), this
+ value can be retrieved from the `authorization_endpoint` property of the JSON
+ file hosted at
+ {samp}`{https://identity-provider}/.well-known/openid-configuration`, where
+ `https://identity-provider` is the base URL of the identity provider.
+
+`openid-jwks-endpoint`
+: The endpoint (URI) of the JWKS service which defines how received ID tokens
+ ([JSON Web Tokens](https://jwt.io/) or JWTs) shall be validated.
+
+ This value should be provided to you by the identity provider. For
+ identity providers that implement [OpenID Connect
+ Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html),
+ this value can be retrieved from the `jwks_uri` property of the JSON
+ file hosted at
+ {samp}`{https://identity-provider}/.well-known/openid-configuration`, where
+ `https://identity-provider` is the base URL of the identity provider.
+
+`openid-issuer`
+: The issuer to expect for all received ID tokens.
+
+ This value should be provided to you by the identity provider. For
+ identity providers that implement [OpenID Connect
+ Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html),
+ this value can be retrieved from the `issuer` property of the JSON
+ file hosted at
+ {samp}`{https://identity-provider}/.well-known/openid-configuration`, where
+ `https://identity-provider` is the base URL of the identity provider.
+
+`openid-client-id`
+: The OpenID client ID which should be submitted to the OpenID service when
+ necessary. This value is typically provided to you by the OpenID service when
+ OpenID credentials are generated for your application.
+
+`openid-redirect-uri`
+: The URI that should be submitted to the OpenID service such that they
+ can redirect the authenticated user back to Guacamole after the
+ authentication process is complete. This must be the full URL that a user
+ would enter into their browser to access Guacamole.
+
+Additional optional properties are available to control how claims within
+received ID tokens are used to derive the user's Guacamole username, any
+associated groups, the OpenID scopes requested when user identities are
+confirmed, and to control the maximum amount of time allowed for various
+aspects of the conversation with the identity provider:
+
+`openid-username-claim-type`
+: The claim type within any valid JWT that contains the authenticated user's
+ username. By default, the "`email`" claim type is used.
+
+`openid-groups-claim-type`
+: The claim type within any valid JWT that contains the list of groups of which
+ the authenticated user is a member. By default, the "`groups`" claim type is
+ used.
+
+`openid-scope`
+: The space-separated list of OpenID scopes to request. OpenID scopes determine
+ the information returned within the OpenID token, and thus affect what values
+ can be used as an authenticated user's username. To be compliant with OpenID,
+ at least "`openid profile`" must be requested. By default, "`openid email
+ profile`" is used.
+
+`openid-allowed-clock-skew`
+: The amount of clock skew tolerated for timestamp comparisons between the
+ Guacamole server and OpenID service clocks, in seconds. By default, clock skew
+ of up to 30 seconds is tolerated.
+
+`openid-max-token-validity`
+: The maximum amount of time that an OpenID token should remain valid, in
+ minutes. By default, each OpenID token remains valid for 300 minutes (5
+ hours).
+
+`openid-max-nonce-validity`
+: The maximum amount of time that a nonce generated by the Guacamole
+ server should remain valid, in minutes. As each OpenID request has a unique
+ nonce value, this imposes an upper limit on the amount of time any particular
+ OpenID request can result in successful authentication within Guacamole. By
+ default, each generated nonce expires after 10 minutes.
+
+(completing-openid-install)=
+
+### Completing the installation
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before OpenID Connect authentication can be used. *Doing this will disconnect
+all active users, so be sure that it is safe to do so prior to attempting
+installation.* When ready, restart your servlet container and give the new
+authentication a try.
+
diff --git a/src/protocol-reference.rst b/src/protocol-reference.rst
new file mode 100644
index 0000000..9e592ea
--- /dev/null
+++ b/src/protocol-reference.rst
@@ -0,0 +1,1205 @@
+Guacamole protocol reference
+============================
+
+Drawing instructions
+--------------------
+
+.. guac:instruction:: arc
+ :sent-by: server
+ :phase: interactive
+
+ The arc instruction adds the specified arc subpath to the existing path,
+ creating a new path if no path exists. The path created can be modified further
+ by other path-type instructions, and finally stroked, filled, and/or closed.
+
+ :arg integer layer:
+ The layer which should have the specified arc subpath added.
+
+ :arg integer x:
+ The X coordinate of the center of the circle containing the arc to be
+ drawn.
+
+ :arg integer y:
+ The Y coordinate of the center of the circle containing the arc to be
+ drawn.
+
+ :arg float radius:
+ The radius of the circle containing the arc to be drawn, in pixels.
+
+ :arg float start:
+ The starting angle of the arc to be drawn, in radians.
+
+ :arg float end:
+ The ending angle of the arc to be drawn, in radians.
+
+ :arg integer negative:
+ Non-zero if the arc should be drawn from START to END in order of
+ decreasing angle, zero otherwise.
+
+.. guac:instruction:: cfill
+ :sent-by: server
+ :phase: interactive
+
+ Fills the current path with the specified color. This instruction completes
+ the current path. Future path instructions will begin a new path.
+
+ :arg integer mask:
+ The channel mask to apply when filling the current path in the
+ specified layer.
+
+ :arg integer layer:
+ The layer whose path should be filled.
+
+ :arg integer r:
+ The red component of the color to use to fill the current path in the
+ specified layer.
+
+ :arg integer g:
+ The green component of the color to use to fill the current path in the
+ specified layer.
+
+ :arg integer b:
+ The blue component of the color to use to fill the current path in the
+ specified layer.
+
+ :arg integer a:
+ The alpha component of the color to use to fill the current path in the
+ specified layer.
+
+.. guac:instruction:: clip
+ :sent-by: server
+ :phase: interactive
+
+ Applies the current path as the clipping path. Future operations will only
+ draw within the current path. Note that future clip instructions will also
+ be limited by this path. To set a completely new clipping path, you must
+ first reset the layer with a reset instruction. If you wish to only reset
+ the clipping path, but preserve the current transform matrix, push the
+ layer state before setting the clipping path, and pop the layer state to
+ reset.
+
+ :arg integer layer:
+ The layer whose clipping path should be set.
+
+.. guac:instruction:: close
+ :sent-by: server
+ :phase: interactive
+
+ Closes the current path by connecting the start and end points with a
+ straight line.
+
+ :arg integer layer:
+ The layer whose path should be closed.
+
+.. guac:instruction:: copy
+ :sent-by: server
+ :phase: interactive
+
+ Copies image data from the specified rectangle of the specified layer or
+ buffer to a different location of another specified layer or buffer.
+
+ :arg integer srclayer:
+ The index of the layer to copy image data from.
+
+ :arg integer srcx:
+ The X coordinate of the upper-left corner of the source rectangle
+ within the source layer.
+
+ :arg integer srcy:
+ The Y coordinate of the upper-left corner of the source rectangle
+ within the source layer.
+
+ :arg integer srcwidth:
+ The width of the source rectangle within the source layer.
+
+ :arg integer srcheight:
+ The height of the source rectangle within the source layer.
+
+ :arg integer mask:
+ The channel mask to apply when drawing the image data on the
+ destination layer.
+
+ :arg integer dstlayer:
+ The index of the layer to draw the image data to.
+
+ :arg integer dstx:
+ The X coordinate of the upper-left corner of the destination within
+ the destination layer.
+
+ :arg integer dsty:
+ The Y coordinate of the upper-left corner of the destination within
+ the destination layer.
+
+.. guac:instruction:: cstroke
+ :sent-by: server
+ :phase: interactive
+
+ Strokes the current path with the specified color. This instruction
+ completes the current path. Future path instructions will begin a new path.
+
+ :arg integer mask:
+ The channel mask to apply when stroking the current path in the
+ specified layer.
+
+ :arg integer layer:
+ The layer whose path should be stroked.
+
+ :arg integer cap:
+ The index of the line cap style to use. This can be either butt (0),
+ round (1), or square (2).
+
+ :arg integer join:
+ The index of the line join style to use. This can be either bevel
+ (0), miter (1), or round (2).
+
+ :arg integer thickness:
+ The thickness of the stroke to draw, in pixels.
+
+ :arg integer r:
+ The red component of the color to use to stroke the current path in
+ the specified layer.
+
+ :arg integer g:
+ The green component of the color to use to stroke the current path in
+ the specified layer.
+
+ :arg integer b:
+ The blue component of the color to use to stroke the current path in
+ the specified layer.
+
+ :arg integer a:
+ The alpha component of the color to use to stroke the current path in
+ the specified layer.
+
+.. guac:instruction:: cursor
+ :sent-by: server
+ :phase: interactive
+
+ Sets the client's cursor to the image data from the specified rectangle of
+ a layer, with the specified hotspot.
+
+ :arg integer x:
+ The X coordinate of the cursor's hotspot.
+
+ :arg integer y:
+ The Y coordinate of the cursor's hotspot.
+
+ :arg integer srclayer:
+ The index of the layer to copy image data from.
+
+ :arg integer srcx:
+ The X coordinate of the upper-left corner of the source rectangle
+ within the source layer.
+
+ :arg integer srcy:
+ The Y coordinate of the upper-left corner of the source rectangle
+ within the source layer.
+
+ :arg integer srcwidth:
+ The width of the source rectangle within the source layer.
+
+ :arg integer srcheight:
+ The height of the source rectangle within the source layer.
+
+.. guac:instruction:: curve
+ :sent-by: server
+ :phase: interactive
+
+ Adds the specified cubic bezier curve subpath.
+
+ :arg integer layer:
+ The layer which should have the specified curve subpath added.
+
+ :arg integer cp1x:
+ The X coordinate of the first control point of the curve.
+
+ :arg integer cp1y:
+ The Y coordinate of the first control point of the curve.
+
+ :arg integer cp2x:
+ The X coordinate of the second control point of the curve.
+
+ :arg integer cp2y:
+ The Y coordinate of the second control point of the curve.
+
+ :arg integer x:
+ The X coordinate of the endpoint of the curve.
+
+ :arg integer y:
+ The Y coordinate of the endpoint of the curve.
+
+.. guac:instruction:: dispose
+ :sent-by: server
+ :phase: interactive
+
+ Removes the specified layer. The specified layer will be recreated as a new
+ layer if it is referenced again.
+
+ :arg integer layer:
+ The layer to remove.
+
+.. guac:instruction:: distort
+ :sent-by: server
+ :phase: interactive
+
+ Sets the given affine transformation matrix to the layer. Unlike transform,
+ this operation is independent of any previously sent transformation matrix.
+ This operation can be undone by setting the layer's transformation matrix
+ to the identity matrix using distort
+
+ :arg integer layer:
+ The layer to distort.
+
+ :arg float a:
+ The matrix value in row 1, column 1.
+
+ :arg float b:
+ The matrix value in row 2, column 1.
+
+ :arg float c:
+ The matrix value in row 1, column 2.
+
+ :arg float d:
+ The matrix value in row 2, column 2.
+
+ :arg float e:
+ The matrix value in row 1, column 3.
+
+ :arg float f:
+ The matrix value in row 2, column 3.
+
+.. guac:instruction:: identity
+ :sent-by: server
+ :phase: interactive
+
+ Resets the transform matrix of the specified layer to the identity matrix.
+
+ :arg integer layer:
+ The layer whose transform matrix should be reset.
+
+.. guac:instruction:: img
+ :sent-by: server
+ :phase: interactive
+
+ Allocates a new stream, associating it with the metadata of an image
+ update, including the image type, the destination layer, and destination
+ coordinates. The contents of the image will later be sent along the stream
+ with blob instructions. The full size of the image need not be known ahead
+ of time.
+
+ :arg integer stream:
+ The index of the stream to allocate.
+
+ :arg string mimetype:
+ The mimetype of the image being sent.
+
+ :arg integer mask:
+ The channel mask to apply when drawing the image data.
+
+ :arg integer layer:
+ The destination layer.
+
+ :arg integer x:
+ The X coordinate of the upper-left corner of the destination within
+ the destination layer.
+
+ :arg integer y:
+ The Y coordinate of the upper-left corner of the destination within
+ the destination layer.
+
+.. guac:instruction:: lfill
+ :sent-by: server
+ :phase: interactive
+
+ Fills the current path with a tiled pattern of the image data from the
+ specified layer. This instruction completes the current path. Future path
+ instructions will begin a new path.
+
+ :arg integer mask:
+ The channel mask to apply when filling the current path in the
+ specified layer.
+
+ :arg integer layer:
+ The layer whose path should be filled.
+
+ :arg integer srclayer:
+ The layer to use as the pattern.
+
+.. guac:instruction:: line
+ :sent-by: server
+ :phase: interactive
+
+ Adds the specified line subpath.
+
+ :arg integer layer:
+ The layer which should have the specified line subpath added.
+
+ :arg integer x:
+ The X coordinate of the endpoint of the line.
+
+ :arg integer y:
+ The Y coordinate of the endpoint of the line.
+
+.. guac:instruction:: lstroke
+ :sent-by: server
+ :phase: interactive
+
+ Strokes the current path with a tiled pattern of the image data from the
+ specified layer. This instruction completes the current path. Future path
+ instructions will begin a new path.
+
+ :arg integer mask:
+ The channel mask to apply when filling the current path in the
+ specified layer.
+
+ :arg integer layer:
+ The layer whose path should be filled.
+
+ :arg integer cap:
+ The index of the line cap style to use. This can be either butt (0),
+ round (1), or square (2).
+
+ :arg integer join:
+ The index of the line join style to use. This can be either bevel
+ (0), miter (1), or round (2).
+
+ :arg integer thickness:
+ The thickness of the stroke to draw, in pixels.
+
+ :arg integer srclayer:
+ The layer to use as the pattern.
+
+.. guac:instruction:: move
+ :sent-by: server
+ :phase: interactive
+
+ Moves the given layer to the given location within the specified parent
+ layer. This operation is applicable only to layers, and cannot be applied
+ to buffers (layers with negative indices). Applying this operation to the
+ default layer (layer 0) also has no effect.
+
+ :arg integer layer:
+ The layer to move.
+
+ :arg integer parent:
+ The layer that should be the parent of the given layer.
+
+ :arg integer x:
+ The X coordinate to move the layer to.
+
+ :arg integer y:
+ The Y coordinate to move the layer to.
+
+ :arg integer z:
+ The relative Z-ordering of this layer. Layers with larger values will
+ appear above layers with smaller values.
+
+.. guac:instruction:: pop
+ :sent-by: server
+ :phase: interactive
+
+ Restores the previous state of the specified layer from the stack. The
+ state restored includes the transformation matrix and clipping path.
+
+ :arg integer layer:
+ The layer whose state should be restored.
+
+.. guac:instruction:: push
+ :sent-by: server
+ :phase: interactive
+
+ Saves the current state of the specified layer to the stack. The state
+ saved includes the current transformation matrix and clipping path.
+
+ :arg integer layer:
+ The layer whose state should be saved.
+
+.. guac:instruction:: rect
+ :sent-by: server
+ :phase: interactive
+
+ Adds a rectangular path to the specified layer.
+
+ :arg integer mask:
+ The channel mask to apply when drawing the image data.
+
+ :arg integer layer:
+ The destination layer.
+
+ :arg integer x:
+ The X coordinate of the upper-left corner of the rectangle to draw.
+
+ :arg integer y:
+ The Y coordinate of the upper-left corner of the rectangle to draw.
+
+ :arg integer width:
+ The width of the rectangle to draw.
+
+ :arg integer height:
+ The width of the rectangle to draw.
+
+.. guac:instruction:: reset
+ :sent-by: server
+ :phase: interactive
+
+ Resets the transformation and clip state of the layer.
+
+ :arg integer layer:
+ The layer whose state should be reset.
+
+.. guac:instruction:: set
+ :sent-by: server
+ :phase: interactive
+
+ Sets the given client-side property to the specified value. Currently there
+ is only one property: miter-limit, the maximum distance between the inner
+ and outer points of a miter joint, proportional to stroke width (if
+ miter-limit is set to 10.0, the default, then the maximum distance between
+ the points of the joint is 10 times the stroke width).
+
+ :arg integer layer:
+ The layer whose property should be set.
+
+ :arg string property:
+ The name of the property to set.
+
+ :arg string value:
+ The value to set the given property to.
+
+.. guac:instruction:: shade
+ :sent-by: server
+ :phase: interactive
+
+ Sets the opacity of the given layer.
+
+ :arg integer layer:
+ The layer whose opacity should be set.
+
+ :arg integer opacity:
+ The opacity of the layer, where 0 is completely transparent, and 255
+ is completely opaque.
+
+.. guac:instruction:: size
+ :sent-by: server
+ :phase: interactive
+
+ Sets the size of the specified layer.
+
+ :arg integer layer:
+ The layer to resize.
+
+ :arg integer width:
+ The new width of the layer
+
+ :arg integer height:
+ The new height of the layer
+
+.. guac:instruction:: start
+ :sent-by: server
+ :phase: interactive
+
+ Starts a new subpath at the specified point.
+
+ :arg integer layer:
+ The layer which should start a new subpath.
+
+ :arg integer x:
+ The X coordinate of the first point of the new subpath.
+
+ :arg integer y:
+ The Y coordinate of the first point of the new subpath.
+
+.. guac:instruction:: transfer
+ :sent-by: server
+ :phase: interactive
+
+ Transfers image data from the specified rectangle of the specified layer or
+ buffer to a different location of another specified layer or buffer, using
+ the specified transfer function.
+
+ For a list of available functions, see the definition of
+ ``guac_transfer_function`` within the `guacamole/protocol-types.h
+ <https://github.com/apache/guacamole-server/blob/master/src/libguac/guacamole/protocol-types.h>`__
+ header included with libguac.
+
+ :arg integer srclayer:
+ The index of the layer to transfer image data from.
+
+ :arg integer srcx:
+ The X coordinate of the upper-left corner of the source rectangle
+ within the source layer.
+
+ :arg integer srcy:
+ The Y coordinate of the upper-left corner of the source rectangle
+ within the source layer.
+
+ :arg integer srcwidth:
+ The width of the source rectangle within the source layer.
+
+ :arg integer srcheight:
+ The height of the source rectangle within the source layer.
+
+ :arg integer function:
+ The index of the transfer function to use.
+
+ For a list of available functions, see the definition of
+ ``guac_transfer_function`` within the `guacamole/protocol-types.h
+ <https://github.com/apache/guacamole-server/blob/master/src/libguac/guacamole/protocol-types.h>`__
+ header included with libguac.
+
+ :arg integer dstlayer:
+ The index of the layer to draw the image data to.
+
+ :arg integer dstx:
+ The X coordinate of the upper-left corner of the destination within
+ the destination layer.
+
+ :arg integer dsty:
+ The Y coordinate of the upper-left corner of the destination within
+ the destination layer.
+
+.. guac:instruction:: transform
+ :sent-by: server
+ :phase: interactive
+
+ Applies the specified transformation matrix to future operations. Unlike
+ distort, this operation is dependent on any previously sent transformation
+ matrices, and only affects future operations. This operation can be undone
+ by setting the layer's transformation matrix to the identity matrix using
+ identity, but image data already drawn will not be affected.
+
+ :arg integer layer:
+ The layer to apply the given transformation matrix to.
+
+ :arg float a:
+ The matrix value in row 1, column 1.
+
+ :arg float b:
+ The matrix value in row 2, column 1.
+
+ :arg float c:
+ The matrix value in row 1, column 2.
+
+ :arg float d:
+ The matrix value in row 2, column 2.
+
+ :arg float e:
+ The matrix value in row 1, column 3.
+
+ :arg float f:
+ The matrix value in row 2, column 3.
+
+Streaming instructions
+----------------------
+
+.. guac:instruction:: ack
+ :sent-by: client,server
+ :phase: interactive
+
+ The ack instruction acknowledges a received data blob, providing a status
+ code and message indicating whether the operation associated with the blob
+ succeeded or failed. A status code other than 0 (``SUCCESS``) implicitly
+ ends the stream.
+
+ :arg integer stream:
+ The index of the stream the corresponding blob was received on.
+
+ :arg string message:
+ A human-readable error message. This typically is not exposed within
+ any user interface, and mainly helps with debugging.
+
+ :arg integer status:
+ The Guacamole status code denoting success or failure. For a list of status
+ codes, see the table in `Status codes <#status-codes>`__.
+
+.. guac:instruction:: argv
+ :sent-by: client,server
+ :phase: interactive
+
+ Allocates a new stream, associating it with the given argument (connection
+ parameter) metadata. The relevant connection parameter data will later be
+ sent along the stream with blob instructions. If sent by the client, this
+ data will be the desired new value of the connection parameter being
+ changed, and will be applied if the server supports changing that
+ connection parameter while the connection is active. If sent by the server,
+ this data will be the current value of a connection parameter being exposed
+ to the client.
+
+ :arg integer stream:
+ The index of the stream to allocate.
+
+ :arg string mimetype:
+ The mimetype of the connection parameter being sent. In most cases,
+ this will be "text/plain".
+
+ :arg string name:
+ The name of the connection parameter whose value is being sent.
+
+.. guac:instruction:: audio
+ :sent-by: client,server
+ :phase: interactive
+
+ Allocates a new stream, associating it with the given audio metadata.
+ Audio data will later be sent along the stream with blob instructions. The
+ mimetype given must be a mimetype previously specified by the client during
+ the handshake procedure. Playback will begin immediately and will continue
+ as long as blobs are received along the stream.
+
+ :arg integer stream:
+ The index of the stream to allocate.
+
+ :arg string mimetype:
+ The mimetype of the audio data being sent.
+
+.. guac:instruction:: blob
+ :sent-by: client,server
+ :phase: interactive
+
+ Sends a blob of data along the given stream. This blob of data is
+ arbitrary, base64-encoded data, and only has meaning to the Guacamole
+ client or server through the metadata assigned to the stream when the
+ stream was allocated.
+
+ :arg integer stream:
+ The index of the stream along which the given data should be sent.
+
+ :arg string data:
+ The base64-encoded data to send.
+
+.. guac:instruction:: clipboard
+ :sent-by: client,server
+ :phase: interactive
+
+ Allocates a new stream, associating it with the given clipboard metadata.
+ The clipboard data will later be sent along the stream with blob
+ instructions. If sent by the client, this data will be the contents of the
+ client-side clipboard. If sent by the server, this data will be the
+ contents of the clipboard within the remote desktop.
+
+ :arg integer stream:
+ The index of the stream to allocate.
+
+ :arg string mimetype:
+ The mimetype of the clipboard data being sent. In most cases, this
+ will be "text/plain".
+
+.. guac:instruction:: end
+ :sent-by: client,server
+ :phase: interactive
+
+ The end instruction terminates an open stream, freeing any client-side or
+ server-side resources. Data sent to a terminated stream will be ignored.
+ Terminating a stream with the end instruction only denotes the end of the
+ stream and does not imply an error.
+
+ :arg integer stream:
+ The index of the stream the corresponding blob was received on.
+
+.. guac:instruction:: file
+ :sent-by: client,server
+ :phase: interactive
+
+ Allocates a new stream, associating it with the given arbitrary file
+ metadata. The contents of the file will later be sent along the stream with
+ blob instructions. The full size of the file need not be known ahead of
+ time.
+
+ :arg integer stream:
+ The index of the stream to allocate.
+
+ :arg string mimetype:
+ The mimetype of the file being sent.
+
+ :arg string filename:
+ The name of the file, as it would be saved on a filesystem.
+
+.. guac:instruction:: pipe
+ :sent-by: client,server
+ :phase: interactive
+
+ Allocates a new stream, associating it with the given arbitrary named pipe
+ metadata. The contents of the pipe will later be sent along the stream with
+ blob instructions. Pipes in the Guacamole protocol are unidirectional,
+ named pipes, very similar to a UNIX FIFO or pipe. It is up to client-side
+ code to handle pipe data appropriately, likely based upon the name of the
+ pipe, which is arbitrary. Pipes may be opened by either the client or the
+ server.
+
+ :arg integer stream:
+ The index of the stream to allocate.
+
+ :arg string mimetype:
+ The mimetype of the data being sent along the pipe.
+
+ :arg string name:
+ The arbitrary name of the pipe, which may have special meaning to
+ client-side code.
+
+.. guac:instruction:: video
+ :sent-by: client,server
+ :phase: interactive
+
+ Allocates a new stream, associating it with the given video metadata.
+ Video data will later be sent along the stream with blob instructions. The
+ mimetype given must be a mimetype previously specified by the client during
+ the handshake procedure. Playback will begin immediately and will continue
+ as long as blobs are received along the stream.
+
+ :arg integer stream:
+ The index of the stream to allocate.
+
+ :arg integer layer:
+ The index of the layer to stream the video data into. The effect of
+ other drawing operations on this layer during playback is undefined,
+ as the client codec implementation may leverage any rendering
+ mechanism it sees fit, including hardware decoding.
+
+ :arg string mimetype:
+ The mimetype of the video data being sent.
+
+Object instructions
+-------------------
+
+.. guac:instruction:: body
+ :sent-by: client,server
+ :phase: interactive
+
+ Allocates a new stream, associating it with the name of a stream previously
+ requested by a get instruction. The contents of the stream will be sent
+ later with blob instructions. The full size of the stream need not be known
+ ahead of time.
+
+ :arg integer object:
+ The index of the object associated with this stream.
+
+ :arg integer stream:
+ The index of the stream to allocate.
+
+ :arg string mimetype:
+ The mimetype of the data being sent.
+
+ :arg string name:
+ The name of the stream associated with the object.
+
+.. guac:instruction:: filesystem
+ :sent-by: server
+ :phase: interactive
+
+ Allocates a new object, associating it with the given arbitrary filesystem
+ metadata. The contents of files and directories within the filesystem will
+ later be sent along streams requested with get instructions or created with
+ put instructions.
+
+ :arg integer object:
+ The index of the object to allocate.
+
+ :arg string name:
+ The name of the filesystem.
+
+.. guac:instruction:: get
+ :sent-by: client,server
+ :phase: interactive
+
+ Requests that a new stream be created, providing read access to the object
+ stream having the given name. The requested stream will be created, in
+ response, with a body instruction.
+
+ Stream names are arbitrary and dictated by the object from which they are
+ requested, with the exception of the root stream of the object itself,
+ which has the reserved name "``/``". The root stream of the object has the
+ mimetype "``application/vnd.glyptodon.guacamole.stream-index+json``", and
+ provides a simple JSON map of available stream names to their corresponding
+ mimetypes. If the object contains a hierarchy of streams, some of these
+ streams may also be
+ "``application/vnd.glyptodon.guacamole.stream-index+json``".
+
+ For example, the ultimate content of the body stream provided in response
+ to a get request for the root stream of an object containing two text
+ streams, "A" and "B", would be the following:
+
+ .. code-block:: json
+
+ {
+ "A" : "text/plain",
+ "B" : "text/plain"
+ }
+
+ :arg integer object:
+ The index of the object to request a stream from.
+
+ :arg string name:
+ The name of the stream being requested from the given object.
+
+.. guac:instruction:: put
+ :sent-by: client,server
+ :phase: interactive
+
+ Allocates a new stream, associating it with the given arbitrary object and
+ stream name. The contents of the stream will later be sent with blob
+ instructions.
+
+ :arg integer object:
+ The index of the object associated with this stream.
+
+ :arg integer stream:
+ The index of the stream to allocate.
+
+ :arg string mimetype:
+ The mimetype of the data being sent.
+
+ :arg string name:
+ The name of the stream within the given object to which data is being
+ sent.
+
+.. guac:instruction:: undefine
+ :sent-by: client,server
+ :phase: interactive
+
+ Undefines an existing object, allowing its index to be reused by another
+ future object. The resource associated with the original object may or may
+ not continue to exist - it simply no longer has an associated object.
+
+ :arg integer object:
+ The index of the object to undefine.
+
+Client handshake instructions
+-----------------------------
+
+.. guac:instruction:: audio
+ :sent-by: client
+ :phase: handshake
+
+ Specifies which audio mimetypes are supported by the client. Each parameter
+ must be a single mimetype, listed in order of client preference, with the
+ optimal mimetype being the first parameter.
+
+.. guac:instruction:: connect
+ :sent-by: client
+ :phase: handshake
+
+ Begins the connection using the previously specified protocol with the
+ given arguments. This is the last instruction sent during the handshake
+ phase.
+
+ The parameters of this instruction correspond exactly to the parameters of
+ the received args instruction. If the received args instruction has, for
+ example, three parameters, the responding connect instruction must also
+ have three parameters.
+
+.. guac:instruction:: image
+ :sent-by: client
+ :phase: handshake
+
+ Specifies which image mimetypes are supported by the client. Each parameter
+ must be a single mimetype, listed in order of client preference, with the
+ optimal mimetype being the first parameter.
+
+ It is expected that the supported mimetypes will include at least
+ "image/png" and "image/jpeg", and the server *may* safely assume that these
+ mimetypes are supported, even if they are absent from the handshake.
+
+.. guac:instruction:: select
+ :sent-by: client
+ :phase: handshake
+
+ Requests that the connection be made using the specified protocol, or to
+ the specified existing connection. Whether a new connection is established
+ or an existing connection is joined depends on whether the ID of an active
+ connection is provided. The Guacamole protocol dictates that the IDs
+ generated for active connections (provided during the handshake of those
+ connections via the `ready instruction <#ready-instruction>`__) must not
+ collide with any supported protocols.
+
+ This is the first instruction sent during the handshake phase.
+
+ :arg string identifier:
+ The name of the protocol to use, such as "vnc" or "rdp", or the ID of
+ the active connection to be joined, as returned via the `ready
+ instruction <#ready-instruction>`__.
+
+.. guac:instruction:: size
+ :sent-by: client
+ :phase: handshake
+
+ Specifies the client's optimal screen size and resolution.
+
+ :arg integer width:
+ The optimal screen width.
+
+ :arg integer height:
+ The optimal screen height.
+
+ :arg integer dpi:
+ The optimal screen resolution, in approximate DPI.
+
+.. guac:instruction:: timezone
+ :sent-by: client
+ :phase: handshake
+
+ Specifies the timezone of the client system, in IANA zone key format. This
+ is a single-value parameter, and may be used by protocols to set the
+ timezone on the remote computer, if the remote system allows the timezone
+ to be configured. This instruction is optional.
+
+ :arg string timezone:
+
+.. guac:instruction:: video
+ :sent-by: client
+ :phase: handshake
+
+ Specifies which video mimetypes are supported by the client. Each parameter
+ must be a single mimetype, listed in order of client preference, with the
+ optimal mimetype being the first parameter.
+
+Server handshake instructions
+-----------------------------
+
+.. guac:instruction:: args
+ :sent-by: server
+ :phase: handshake
+
+ Reports the expected format of the argument list for the protocol requested
+ by the client. This message can be sent by the server during the handshake
+ phase only.
+
+ The first parameter of this instruction will be the protocol version
+ supported by the server. This is used to negotiate protocol compatibility
+ between the client and the server, with the highest supported protocol by
+ both sides being chosen. Versions of Guacamole prior to 1.1.0 do not
+ support protocol version negotiation, and will silently ignore this
+ instruction.
+
+ The remaining parameters of the args instruction are the names of all
+ connection parameters accepted by the server for the protocol selected by
+ the client, in order. The client's responding connect instruction must
+ contain the values of each of these parameters in the same order.
+
+Control instructions
+--------------------
+
+.. guac:instruction:: disconnect
+ :sent-by: client,server
+ :phase: handshake,interactive
+
+ Notifies the client or server that the connection is about to be closed.
+ This message can be sent during any phase, and takes no parameters.
+
+.. guac:instruction:: nop
+ :sent-by: client,server
+ :phase: interactive
+
+ The "nop" instruction does absolutely nothing, has no parameters, and is
+ universally ignored by both Guacamole clients and servers. Its main use is
+ as a keep-alive signal, and may be sent by guacd, client plugins, or web
+ applications when there is no activity to ensure the socket is not closed
+ due to timeout.
+
+.. guac:instruction:: sync
+ :sent-by: client,server
+ :phase: interactive
+
+ Reports that all operations as of the given server-relative timestamp have
+ been completed. Both client and server are expected to occasionally send
+ sync to report on current operation execution state, with the server using
+ sync to denote the end of a logical frame.
+
+ If a sync is received from the server, the client must respond with a
+ corresponding sync once all previous operations have been completed, or the
+ server may stop sending updates until the client catches up. For the
+ client, sending a sync with a timestamp newer than any timestamp received
+ from the server is an error.
+
+ :arg integer timestamp:
+ A valid server-relative timestamp.
+
+Server control instructions
+---------------------------
+
+.. guac:instruction:: error
+ :sent-by: server
+ :phase: handshake,interactive
+
+ Notifies the client that the connection is about to be closed due to the
+ specified error. This message can be sent by the server during any phase.
+
+ :arg string message:
+ An arbitrary message describing the error
+
+ :arg integer status:
+ The Guacamole status code describing the error. For a list of status
+ codes, see the table in `Status codes <#status-codes>`__.
+
+.. guac:instruction:: log
+ :sent-by: server
+ :phase: interactive
+
+ The log instruction sends an arbitrary string for debugging purposes. This
+ instruction will be ignored by Guacamole clients, but can be seen in
+ protocol dumps if such dumps become necessary. Sending a log instruction
+ can help add context when searching for the cause of a fault in protocol
+ support.
+
+ :arg string message:
+ An arbitrary, human-readable message.
+
+.. guac:instruction:: mouse
+ :sent-by: server
+ :phase: interactive
+
+ Reports that a user on the current connection has moved the mouse to the
+ given coordinates.
+
+ :arg integer x:
+ The current X coordinate of the mouse pointer.
+
+ :arg integer y:
+ The current Y coordinate of the mouse pointer.
+
+.. guac:instruction:: ready
+ :sent-by: server
+ :phase: handshake
+
+ The ready instruction sends the ID of a new connection and marks the
+ beginning of the interactive phase of a new, successful connection. The ID
+ sent is a completely arbitrary string, and has no standard format. It must
+ be unique from all existing and future connections and may not match the
+ name of any installed protocol support.
+
+ :arg string identifier:
+ An arbitrary, unique identifier for the current connection. This
+ identifier must be unique from all existing and future connections,
+ and may not match the name of any installed protocol support (such as
+ "vnc" or "rdp").
+
+Input/Event instructions
+------------------------
+
+.. guac:instruction:: key
+ :sent-by: client
+ :phase: interactive
+
+ Sends the specified key press or release event.
+
+ :arg integer keysym:
+ The `X11 keysym <http://www.x.org/wiki/KeySyms>`__ of the key being
+ pressed or released.
+
+ :arg integer pressed:
+ 0 if the key is not pressed, 1 if the key is pressed.
+
+.. guac:instruction:: mouse
+ :sent-by: client
+ :phase: interactive
+
+ Sends the specified mouse movement or button press or release event (or
+ combination thereof).
+
+ :arg integer x:
+ The current X coordinate of the mouse pointer.
+
+ :arg integer y:
+ The current Y coordinate of the mouse pointer.
+
+ :arg integer mask:
+ The button mask, representing the pressed or released status of each
+ mouse button.
+
+.. guac:instruction:: size
+ :sent-by: client
+ :phase: interactive
+
+ Specifies that the client's optimal screen size has changed from what was
+ specified during the handshake, or from previously-sent "size"
+ instructions.
+
+ :arg integer width:
+ The new, optimal screen width.
+
+ :arg integer height:
+ The new, optimal screen height.
+
+Status codes
+------------
+
+Several Guacamole instructions, and various other internals of the Guacamole
+core, use a common set of numeric status codes. These codes denote success or
+failure of operations, and can be rendered by user interfaces in a
+human-readable way.
+
+0 (``SUCCESS``)
+ The operation succeeded. No error.
+
+256 (``UNSUPPORTED``)
+ The requested operation is unsupported.
+
+512 (``SERVER_ERROR``)
+ An internal error occurred, and the operation could not be performed.
+
+513 (``SERVER_BUSY``)
+ The operation could not be performed because the server is busy.
+
+514 (``UPSTREAM_TIMEOUT``)
+ The upstream server is not responding. In most cases, the upstream server
+ is the remote desktop server.
+
+515 (``UPSTREAM_ERROR``)
+ The upstream server encountered an error. In most cases, the upstream
+ server is the remote desktop server.
+
+516 (``RESOURCE_NOT_FOUND``)
+ An associated resource, such as a file or stream, could not be found, and
+ thus the operation failed.
+
+517 (``RESOURCE_CONFLICT``)
+ A resource is already in use or locked, preventing the requested operation.
+
+518 (``RESOURCE_CLOSED``)
+ The requested operation cannot continue because the associated resource has
+ been closed.
+
+519 (``UPSTREAM_NOT_FOUND``)
+ The upstream server does not appear to exist, or cannot be reached over the
+ network. In most cases, the upstream server is the remote desktop server.
+
+520 (``UPSTREAM_UNAVAILABLE``)
+ The upstream server is refusing to service connections. In most cases, the
+ upstream server is the remote desktop server.
+
+521 (``SESSION_CONFLICT``)
+ The session within the upstream server has ended because it conflicts with
+ another session. In most cases, the upstream server is the remote desktop
+ server.
+
+522 (``SESSION_TIMEOUT``)
+ The session within the upstream server has ended because it appeared to be
+ inactive. In most cases, the upstream server is the remote desktop server.
+
+523 (``SESSION_CLOSED``)
+ The session within the upstream server has been forcibly closed. In most
+ cases, the upstream server is the remote desktop server.
+
+768 (``CLIENT_BAD_REQUEST``)
+ The parameters of the request are illegal or otherwise invalid.
+
+769 (``CLIENT_UNAUTHORIZED``)
+ Permission was denied, because the user is not logged in. Note that the
+ user may be logged into Guacamole, but still not logged in with respect to
+ the remote desktop server.
+
+771 (``CLIENT_FORBIDDEN``)
+ Permission was denied, and logging in will not solve the problem.
+
+776 (``CLIENT_TIMEOUT``)
+ The client (usually the user of Guacamole or their browser) is taking too
+ long to respond.
+
+781 (``CLIENT_OVERRUN``)
+ The client has sent more data than the protocol allows.
+
+783 (``CLIENT_BAD_TYPE``)
+ The client has sent data of an unexpected or illegal type.
+
+797 (``CLIENT_TOO_MANY``)
+ The client is already using too many resources. Existing resources must be
+ freed before further requests are allowed.
+
diff --git a/src/radius-auth.md b/src/radius-auth.md
new file mode 100644
index 0000000..da48d60
--- /dev/null
+++ b/src/radius-auth.md
@@ -0,0 +1,197 @@
+RADIUS Authentication
+=====================
+
+Guacamole supports delegating authentication to a RADIUS service, such as
+FreeRADIUS, to validate username and password combinations, and to support
+multi-factor authentication. This authentication method must be layered on top
+of some other authentication extension, such as those available from the main
+project website, in order to provide access to actual connections.
+
+(radius-downloading)=
+
+Downloading the RADIUS authentication extension
+-----------------------------------------------
+
+The RADIUS extension depends on software that is covered by a LGPL license,
+which is incompatible with the Apache 2.0 license under which Guacamole is
+licensed. Due to this dependency, the Guacamole project cannot distribute
+binary versions of the RADIUS extension. If you want to use this extension you
+will need to build the code - or at least the RADIUS extension yourself. Build
+instructions can be found in the section [](installing-guacamole).
+
+(installing-radius-auth)=
+
+Installing RADIUS authentication
+--------------------------------
+
+The RADIUS extension must be explicitly enabled during build time in order to
+generate the binaries and resulting JAR file. This is done by adding the flag
+`-Plgpl-extensions` to the Maven command line during the build, and should
+result in the output below:
+
+```console
+$ mvn clean package -Plgpl-extensions
+[INFO] --- maven-assembly-plugin:2.5.3:single (make-source-archive) @ guacamole-client ---
+[INFO] Reading assembly descriptor: project-assembly.xml
+[INFO] Building tar: /home/guac/guacamole-client/target/guacamole-client-1.3.0.tar.gz
+[INFO] ------------------------------------------------------------------------
+[INFO] Reactor Summary:
+[INFO]
+[INFO] guacamole-common .................................. SUCCESS [6.037s]
+[INFO] guacamole-ext ..................................... SUCCESS [5.382s]
+[INFO] guacamole-common-js ............................... SUCCESS [0.751s]
+[INFO] guacamole ......................................... SUCCESS [9.767s]
+[INFO] guacamole-auth-cas ................................ SUCCESS [2.811s]
+[INFO] guacamole-auth-duo ................................ SUCCESS [2.441s]
+[INFO] guacamole-auth-header ............................. SUCCESS [1.875s]
+[INFO] guacamole-auth-jdbc ............................... SUCCESS [0.277s]
+[INFO] guacamole-auth-jdbc-base .......................... SUCCESS [2.144s]
+[INFO] guacamole-auth-jdbc-mysql ......................... SUCCESS [5.637s]
+[INFO] guacamole-auth-jdbc-postgresql .................... SUCCESS [5.465s]
+[INFO] guacamole-auth-jdbc-sqlserver ..................... SUCCESS [5.398s]
+[INFO] guacamole-auth-jdbc-dist .......................... SUCCESS [0.824s]
+[INFO] guacamole-auth-ldap ............................... SUCCESS [2.743s]
+[INFO] guacamole-auth-noauth ............................. SUCCESS [0.964s]
+[INFO] guacamole-auth-openid ............................. SUCCESS [2.533s]
+[INFO] guacamole-example ................................. SUCCESS [0.888s]
+[INFO] guacamole-playback-example ........................ SUCCESS [0.628s]
+[INFO] guacamole-auth-radius ............................. SUCCESS [17.729s]
+[INFO] guacamole-client .................................. SUCCESS [5.645s]
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD SUCCESS
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 1:20.134s
+[INFO] Finished at: Wed Jan 31 09:45:41 EST 2018
+[INFO] Final Memory: 47M/749M
+[INFO] ------------------------------------------------------------------------
+$
+```
+
+After the build completes successfully, the extension will be in the
+`extensions/guacamole-auth-radius/target/` directory, and will be called
+guacamole-auth-radius-1.3.0.jar. This extension file can be copied to the
+`GUACAMOLE_HOME/extensions` directory. *If you are unsure where
+`GUACAMOLE_HOME` is located on your system, please consult
+[](configuring-guacamole) before proceeding.*
+
+Extensions are loaded in alphabetical order, and authentication is performed in
+the order in which the extensions were loaded. If you are stacking the RADIUS
+extension with another extension, like the JDBC extension, in order to store
+connection information, you may need to change the name of the RADIUS extension
+such that it is evaluated prior to the JDBC extension - otherwise an
+authentication failure in one of the previous modules may block the RADIUS
+module from ever being evaluated.
+
+To install the RADIUS authentication extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+ exist.
+
+2. Copy `guacamole-auth-radius-1.3.0.jar` into `GUACAMOLE_HOME/extensions`.
+
+3. Configure Guacamole to use RADIUS authentication, as described below.
+
+(guac-radius-config)=
+
+Configuring Guacamole for RADIUS authentication
+-----------------------------------------------
+
+This extension provides several configuration properties in order to
+communicate properly with the RADIUS server to which it needs to authenticate.
+It is important that you know several key pieces of information about the
+RADIUS server - at a minimum, the server name or IP, the authentication port,
+the authentication protocol in use by the server, and the shared secret for the
+RADIUS client. If you are responsible for the RADIUS server, you'll need to
+properly configure these items to get Guacamole to authenticate properly. If
+you're not responsible for the RADIUS server you will need to work with the
+administrator to get all of the necessary configuration items for the server.
+These items will need to be configured in the
+[`guacamole.properties`](initial-setup) file.
+
+`radius-hostname`
+: The RADIUS server to authenticate against. If not specified, localhost will
+ be used.
+
+`radius-auth-port`
+: The RADIUS authentication port on which the RADIUS service is is listening.
+ If not specified, the default of 1812 will be used.
+
+`radius-shared-secret`
+: The shared secret to use when talking to the RADIUS server. This parameter is
+ required and the extension will not load if this is not specified.
+
+`radius-auth-protocol`
+: The authentication protocol to use when talking to the RADIUS server. This
+ parameter is required for the extension to operate. Supported values are:
+ pap, chap, mschapv1, mschapv2, eap-md5, eap-tls, and eap-ttls. Support for
+ PEAP is implemented inside the extension, but, due to a regression in the
+ JRadius implementation, it is currently broken. Also, if you specify eap-ttls
+ you will also need to specify the `radius-eap-ttls-inner-protocol` parameter
+ in order to properly configure the protocol used inside the EAP TTLS tunnel.
+
+`radius-key-file`
+: The combination certificate and private key pair to use for TLS-based RADIUS
+ protocols that require a client-side certificate. This parameter should specify
+ the absolute path to the file. By default the extension will look for a file
+ called `radius.key` in the `GUACAMOLE_HOME` directory.
+
+`radius-key-type`
+: The file type of the keystore specified by the `radius-key-file` parameter.
+ Valid keystore types are pem, jceks, jks, and pkcs12. If not specified, this
+ defaults to pkcs12, the default used by the JRadius library.
+
+`radius-key-password`
+: The password of the private key specified in the `radius-key-file` parameter.
+ By default the extension will not use any password when trying to open the
+ key file.
+
+`radius-ca-file`
+: The absolute path to the file that stores the certificate authority
+ certificates for encrypted connections to the RADIUS server. By default a
+ file with the name ca.crt in the `GUACAMOLE_HOME` directory will be used.
+
+`radius-ca-type`
+: The file type of keystore used for the certificate authority. Valid formats
+ are pem, jceks, jks, and pkcs12. If not specified this defaults to pem.
+
+`radius-ca-password`
+: The password used to protect the certificate authority store, if any. If
+ unspecified the extension will attempt to read the CA store without any
+ password.
+
+`radius-trust-all`
+: This parameter controls whether or not the RADIUS extension should trust all
+ certificates or verify them against known good certificate authorities. Set
+ to true to allow the RADIUS server to connect without validating
+ certificates. The default is false, which causes certificates to be
+ validated.
+
+`radius-retries`
+: The number of times the client will retry the connection to the RADIUS server
+ and not receive a response before giving up. By default the client will try
+ the connection at most 5 times.
+
+`radius-timeout`
+: The timeout for a RADIUS connection in seconds. By default the client will
+ wait for a response from the server for at most 60 seconds.
+
+`radius-eap-ttls-inner-protocol`
+: When EAP-TTLS is used, this parameter specifies the inner (tunneled) protocol
+ to use talking to the RADIUS server. It is required when the
+ `radius-auth-protocol` parameter is set to eap-ttls. If the
+ `radius-auth-protocol` value is set to something other than eap-ttls, this
+ parameter has no effect and will be ignored. Valid options for this are any of
+ the values for `radius-auth-protocol`, except for eap-ttls.
+
+(completing-radius-install)=
+
+Completing the installation
+---------------------------
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before HTTP header authentication can be used. *Doing this will disconnect all
+active users, so be sure that it is safe to do so prior to attempting
+installation.* When ready, restart your servlet container and give the new
+authentication a try.
+
diff --git a/src/references/instructions/client/control/disconnect.xml b/src/references/instructions/client/control/disconnect.xml
deleted file mode 100644
index 3e9f8b8..0000000
--- a/src/references/instructions/client/control/disconnect.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="client-disconnect-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>disconnect</title>
-
- <indexterm>
- <primary>disconnect</primary>
- </indexterm>
- <para>Notifies the server that the connection is about to be closed by the
- client. This message can be sent by the client during any phase, and
- takes no parameters.</para>
-
-</section>
diff --git a/src/references/instructions/client/control/nop.xml b/src/references/instructions/client/control/nop.xml
deleted file mode 100644
index 41a11d9..0000000
--- a/src/references/instructions/client/control/nop.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="client-nop-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>nop</title>
- <indexterm>
- <primary>nop</primary>
- </indexterm>
- <para>The client "nop" instruction does absolutely nothing, has no parameters, and is
- universally ignored by the Guacamole server. Its main use is as a keep-alive signal, and may
- be sent by Guacamole clients when there is no activity to ensure the socket is not closed
- due to timeout.</para>
-</section>
diff --git a/src/references/instructions/client/control/sync.xml b/src/references/instructions/client/control/sync.xml
deleted file mode 100644
index 774a462..0000000
--- a/src/references/instructions/client/control/sync.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="client-sync-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>sync</title>
- <indexterm>
- <primary>sync</primary>
- </indexterm>
- <para>Reports that all operations as of the given server-relative timestamp
- have been completed. If a sync is received from the server, the client
- must respond with a corresponding sync once all previous operations have
- been completed, or the server may stop sending updates until the client
- catches up. For the client, sending a sync with a timestamp newer than
- any timestamp received from the server is an error.</para>
- <para>Both client and server are expected to occasionally send sync to
- report on current operation execution state.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>timestamp</parameter></term>
- <listitem>
- <para>A valid server-relative timestamp.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/event/key.xml b/src/references/instructions/client/event/key.xml
deleted file mode 100644
index 926768f..0000000
--- a/src/references/instructions/client/event/key.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="key-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>key</title>
-
- <indexterm>
- <primary>key</primary>
- </indexterm>
- <para>Sends the specified key press or release event.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>keysym</parameter></term>
- <listitem>
- <para>The <link xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="http://www.x.org/wiki/KeySyms">X11
- keysym</link> of the key being pressed or
- released.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>pressed</parameter></term>
- <listitem>
- <para>0 if the key is not pressed, 1 if the key is
- pressed.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/event/mouse.xml b/src/references/instructions/client/event/mouse.xml
deleted file mode 100644
index 84ddabf..0000000
--- a/src/references/instructions/client/event/mouse.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="client-mouse-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>mouse</title>
-
- <indexterm>
- <primary>mouse</primary>
- </indexterm>
- <para>Sends the specified mouse movement or button press or release event (or
- combination thereof).</para>
- <variablelist>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The current X coordinate of the mouse pointer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The current Y coordinate of the mouse pointer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mask</parameter></term>
- <listitem>
- <para>The button mask, representing the pressed or released
- status of each mouse button.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/event/size.xml b/src/references/instructions/client/event/size.xml
deleted file mode 100644
index 871c578..0000000
--- a/src/references/instructions/client/event/size.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="size-event-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>size</title>
- <indexterm>
- <primary>size</primary>
- </indexterm>
- <para>Specifies that the client's optimal screen size has changed from what was specified during
- the handshake, or from previously-sent "size" instructions.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>width</parameter></term>
- <listitem>
- <para>The new, optimal screen width.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>height</parameter></term>
- <listitem>
- <para>The new, optimal screen height.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/handshake/audio.xml b/src/references/instructions/client/handshake/audio.xml
deleted file mode 100644
index d1b9a27..0000000
--- a/src/references/instructions/client/handshake/audio.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="audio-handshake-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>audio</title>
- <indexterm>
- <primary>audio</primary>
- </indexterm>
- <para>Specifies which audio mimetypes are supported by the client. Each
- parameter must be a single mimetype, listed in order of client
- preference, with the optimal mimetype being the first parameter.</para>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/handshake/connect.xml b/src/references/instructions/client/handshake/connect.xml
deleted file mode 100644
index f59ce83..0000000
--- a/src/references/instructions/client/handshake/connect.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="connect-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>connect</title>
-
- <indexterm>
- <primary>connect</primary>
- </indexterm>
- <para>Begins the connection using the previously specified protocol with the
- given arguments. This is the last instruction sent during the handshake
- phase.</para>
- <para>The parameters of this instruction correspond exactly to the
- parameters of the received args instruction. If the received args
- instruction has, for example, three parameters, the responding connect
- instruction must also have three parameters.</para>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/handshake/image.xml b/src/references/instructions/client/handshake/image.xml
deleted file mode 100644
index f50477b..0000000
--- a/src/references/instructions/client/handshake/image.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="image-handshake-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>image</title>
- <indexterm>
- <primary>image</primary>
- </indexterm>
- <para>Specifies which image mimetypes are supported by the client. Each parameter must be a
- single mimetype, listed in order of client preference, with the optimal mimetype being the
- first parameter.</para>
- <para>It is expected that the supported mimetypes will include at least "image/png" and
- "image/jpeg", and the server <emphasis>may</emphasis> safely assume that these mimetypes are
- supported, even if they are absent from the handshake.</para>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/handshake/select.xml b/src/references/instructions/client/handshake/select.xml
deleted file mode 100644
index a56a9e0..0000000
--- a/src/references/instructions/client/handshake/select.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="select-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>select</title>
-
- <indexterm>
- <primary>select</primary>
- </indexterm>
- <para>Requests that the connection be made using the specified protocol, or to the specified
- existing connection. Whether a new connection is established or an existing connection is
- joined depends on whether the ID of an active connection is provided. The Guacamole protocol
- dictates that the IDs generated for active connections (provided during the handshake of
- those connections via the <link xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="ready-instruction">ready instruction</link>) must not collide with any
- supported protocols.</para>
- <para>This is the first instruction sent during the handshake phase.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>ID</parameter></term>
- <listitem>
- <para>The name of the protocol to use, such as "vnc" or "rdp", or the ID of the
- active connection to be joined, as returned via the <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="ready-instruction">ready
- instruction</link>.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/handshake/size.xml b/src/references/instructions/client/handshake/size.xml
deleted file mode 100644
index 3041236..0000000
--- a/src/references/instructions/client/handshake/size.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="size-handshake-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>size</title>
- <indexterm>
- <primary>size</primary>
- </indexterm>
- <para>Specifies the client's optimal screen size and resolution.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>width</parameter></term>
- <listitem>
- <para>The optimal screen width.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>height</parameter></term>
- <listitem>
- <para>The optimal screen height.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>dpi</parameter></term>
- <listitem>
- <para>The optimal screen resolution, in approximate DPI.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/handshake/timezone.xml b/src/references/instructions/client/handshake/timezone.xml
deleted file mode 100644
index eea4fe2..0000000
--- a/src/references/instructions/client/handshake/timezone.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="timezone-handshake-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>timezone</title>
- <indexterm>
- <primary>timezone</primary>
- </indexterm>
- <para>Specifies the timezone of the client system, in IANA zone key format.
- This is a single-value parameter, and may be used by protocols to
- set the timezone on the remote computer, if the remote system allows
- the timezone to be configured. This instruction is optional.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>timezone</parameter></term>
- <listiem>
- <para>A valid IANA time zone key that indicates the time zone
- that the client is currently using.</para>
- </listiem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/client/handshake/video.xml b/src/references/instructions/client/handshake/video.xml
deleted file mode 100644
index 71bc3db..0000000
--- a/src/references/instructions/client/handshake/video.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="video-handshake-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>video</title>
- <indexterm>
- <primary>video</primary>
- </indexterm>
- <para>Specifies which video mimetypes are supported by the client. Each
- parameter must be a single mimetype, listed in order of client
- preference, with the optimal mimetype being the first parameter.</para>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/control/disconnect.xml b/src/references/instructions/server/control/disconnect.xml
deleted file mode 100644
index 7cca158..0000000
--- a/src/references/instructions/server/control/disconnect.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="server-disconnect-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>disconnect</title>
- <indexterm>
- <primary>disconnect</primary>
- </indexterm>
- <para>Notifies the client that the connection is about to be closed by the server. This message
- can be sent by the server during any phase, and takes no parameters.</para>
-</section>
diff --git a/src/references/instructions/server/control/error.xml b/src/references/instructions/server/control/error.xml
deleted file mode 100644
index 378fae4..0000000
--- a/src/references/instructions/server/control/error.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="error-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>error</title>
-
- <indexterm>
- <primary>error</primary>
- </indexterm>
- <para>Notifies the client that the connection is about to be closed due to
- the specified error. This message can be sent by the server during any
- phase.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>text</parameter></term>
- <listitem>
- <para>An arbitrary message describing the error</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>status</parameter></term>
- <listitem>
- <para>The Guacamole status code describing the error. For a list of status codes,
- see the table in <xref xmlns:xlink="http://www.w3.org/1999/xlink"
- linkend="status-codes"/>.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/control/log.xml b/src/references/instructions/server/control/log.xml
deleted file mode 100644
index a06f905..0000000
--- a/src/references/instructions/server/control/log.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="log-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>log</title>
- <indexterm>
- <primary>log</primary>
- </indexterm>
- <para>The log instruction sends an arbitrary string for debugging purposes. This instruction
- will be ignored by Guacamole clients, but can be seen in protocol dumps if such dumps become
- necessary. Sending a log instruction can help add context when searching for the cause of a
- fault in protocol support.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>message</parameter></term>
- <listitem>
- <para>An arbitrary, human-readable message.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/control/mouse.xml b/src/references/instructions/server/control/mouse.xml
deleted file mode 100644
index 0b569d0..0000000
--- a/src/references/instructions/server/control/mouse.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="server-mouse-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>mouse</title>
- <indexterm>
- <primary>mouse</primary>
- </indexterm>
- <para>Reports that a user on the current connection has moved the mouse to the given
- coordinates.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The current X coordinate of the mouse pointer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The current Y coordinate of the mouse pointer.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/control/nop.xml b/src/references/instructions/server/control/nop.xml
deleted file mode 100644
index bf7486e..0000000
--- a/src/references/instructions/server/control/nop.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="server-nop-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>nop</title>
- <indexterm>
- <primary>nop</primary>
- </indexterm>
- <para>The server "nop" instruction does absolutely nothing, has no parameters, and is
- universally ignored by Guacamole clients. Its main use is as a keep-alive signal, and may be
- sent by guacd or client plugins when there is no activity to ensure the socket is not closed
- due to timeout.</para>
-</section>
diff --git a/src/references/instructions/server/control/ready.xml b/src/references/instructions/server/control/ready.xml
deleted file mode 100644
index de744de..0000000
--- a/src/references/instructions/server/control/ready.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="ready-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>ready</title>
- <indexterm>
- <primary>ready</primary>
- </indexterm>
- <para>The ready instruction sends the ID of a new connection and marks the beginning of the
- interactive phase of a new, successful connection. The ID sent is a completely arbitrary
- string, and has no standard format. It must be unique from all existing and future
- connections and may not match the name of any installed protocol support.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>ID</parameter></term>
- <listitem>
- <para>An arbitrary, unique identifier for the current connection. This identifier
- must be unique from all existing and future connections, and may not match the
- name of any installed protocol support (such as "vnc" or "rdp").</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/control/sync.xml b/src/references/instructions/server/control/sync.xml
deleted file mode 100644
index 013ec0c..0000000
--- a/src/references/instructions/server/control/sync.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="server-sync-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>sync</title>
- <indexterm>
- <primary>sync</primary>
- </indexterm>
- <para>Indicates that the given timestamp is the current timestamp as of all
- previous operations. The client must respond to every sync instruction
- received.</para>
- <para>Both client and server are expected to occasionally send sync to
- report on current operation execution state.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>timestamp</parameter></term>
- <listitem>
- <para>A valid server-relative timestamp.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/arc.xml b/src/references/instructions/server/drawing/arc.xml
deleted file mode 100644
index af4f420..0000000
--- a/src/references/instructions/server/drawing/arc.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="arc-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>arc</title>
- <indexterm>
- <primary>arc</primary>
- </indexterm>
- <para>The arc instruction adds the specified arc subpath to the existing
- path, creating a new path if no path exists. The path created can be
- modified further by other path-type instructions, and finally stroked,
- filled, and/or closed.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer which should have the specified arc subpath
- added.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The X coordinate of the center of the circle containing
- the arc to be drawn.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The Y coordinate of the center of the circle containing
- the arc to be drawn.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>radius</parameter></term>
- <listitem>
- <para>The radius of the circle containing the arc to be drawn,
- in pixels.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>start</parameter></term>
- <listitem>
- <para>The starting angle of the arc to be drawn, in
- radians.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>end</parameter></term>
- <listitem>
- <para>The ending angle of the arc to be drawn, in
- radians.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>negative</parameter></term>
- <listitem>
- <para>Non-zero if the arc should be drawn from START to END in
- order of decreasing angle, zero otherwise.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/cfill.xml b/src/references/instructions/server/drawing/cfill.xml
deleted file mode 100644
index 1990e6e..0000000
--- a/src/references/instructions/server/drawing/cfill.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="cfill-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>cfill</title>
- <indexterm>
- <primary>cfill</primary>
- </indexterm>
- <para>Fills the current path with the specified color. This instruction
- completes the current path. Future path instructions will begin a new
- path.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>mask</parameter></term>
- <listitem>
- <para>The channel mask to apply when filling the current path in
- the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose path should be filled.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>r</parameter></term>
- <listitem>
- <para>The red component of the color to use to fill the current
- path in the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>g</parameter></term>
- <listitem>
- <para>The green component of the color to use to fill the
- current path in the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>b</parameter></term>
- <listitem>
- <para>The blue component of the color to use to fill the current
- path in the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>a</parameter></term>
- <listitem>
- <para>The alpha component of the color to use to fill the
- current path in the specified layer.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/clip.xml b/src/references/instructions/server/drawing/clip.xml
deleted file mode 100644
index 668041e..0000000
--- a/src/references/instructions/server/drawing/clip.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="clip-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>clip</title>
-
- <indexterm>
- <primary>clip</primary>
- </indexterm>
- <para>Applies the current path as the clipping path. Future operations will
- only draw within the current path. Note that future clip instructions
- will also be limited by this path. To set a completely new clipping path,
- you must first reset the layer with a reset instruction. If you wish to
- only reset the clipping path, but preserve the current transform matrix,
- push the layer state before setting the clipping path, and pop the layer
- state to reset.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose clipping path should be set.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/close.xml b/src/references/instructions/server/drawing/close.xml
deleted file mode 100644
index d55894b..0000000
--- a/src/references/instructions/server/drawing/close.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="close-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>close</title>
-
- <indexterm>
- <primary>close</primary>
- </indexterm>
- <para>Closes the current path by connecting the start and end points with a
- straight line.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose path should be closed.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/copy.xml b/src/references/instructions/server/drawing/copy.xml
deleted file mode 100644
index 58caa7d..0000000
--- a/src/references/instructions/server/drawing/copy.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="copy-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>copy</title>
-
- <indexterm>
- <primary>copy</primary>
- </indexterm>
- <para>Copies image data from the specified rectangle of the specified layer
- or buffer to a different location of another specified layer or
- buffer.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>srclayer</parameter></term>
- <listitem>
- <para>The index of the layer to copy image data from.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcx</parameter></term>
- <listitem>
- <para>The X coordinate of the upper-left corner of the source
- rectangle within the source layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcy</parameter></term>
- <listitem>
- <para>The Y coordinate of the upper-left corner of the source
- rectangle within the source layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcwidth</parameter></term>
- <listitem>
- <para>The width of the source rectangle within the source
- layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcheight</parameter></term>
- <listitem>
- <para>The height of the source rectangle within the source
- layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mask</parameter></term>
- <listitem>
- <para>The channel mask to apply when drawing the image data on
- the destination layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>dstlayer</parameter></term>
- <listitem>
- <para>The index of the layer to draw the image data to.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>dstx</parameter></term>
- <listitem>
- <para>The X coordinate of the upper-left corner of the
- destination within the destination layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>dsty</parameter></term>
- <listitem>
- <para>The Y coordinate of the upper-left corner of the
- destination within the destination layer.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/cstroke.xml b/src/references/instructions/server/drawing/cstroke.xml
deleted file mode 100644
index ab19215..0000000
--- a/src/references/instructions/server/drawing/cstroke.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="cstroke-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>cstroke</title>
-
- <indexterm>
- <primary>cstroke</primary>
- </indexterm>
- <para>Strokes the current path with the specified color. This instruction
- completes the current path. Future path instructions will begin a new
- path.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>mask</parameter></term>
- <listitem>
- <para>The channel mask to apply when stroking the current path
- in the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose path should be stroked.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>cap</parameter></term>
- <listitem>
- <para>The index of the line cap style to use. This can be either
- butt (0), round (1), or square (2).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>join</parameter></term>
- <listitem>
- <para>The index of the line join style to use. This can be
- either bevel (0), miter (1), or round (2).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>thickness</parameter></term>
- <listitem>
- <para>The thickness of the stroke to draw, in pixels.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>r</parameter></term>
- <listitem>
- <para>The red component of the color to use to stroke the
- current path in the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>g</parameter></term>
- <listitem>
- <para>The green component of the color to use to stroke the
- current path in the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>b</parameter></term>
- <listitem>
- <para>The blue component of the color to use to stroke the
- current path in the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>a</parameter></term>
- <listitem>
- <para>The alpha component of the color to use to stroke the
- current path in the specified layer.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/cursor.xml b/src/references/instructions/server/drawing/cursor.xml
deleted file mode 100644
index 94017b9..0000000
--- a/src/references/instructions/server/drawing/cursor.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="cursor-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>cursor</title>
- <para>Sets the client's cursor to the image data from the specified
- rectangle of a layer, with the specified hotspot.</para>
- <indexterm>
- <primary>cursor</primary>
- </indexterm>
- <variablelist>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The X coordinate of the cursor's hotspot.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The Y coordinate of the cursor's hotspot.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srclayer</parameter></term>
- <listitem>
- <para>The index of the layer to copy image data from.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcx</parameter></term>
- <listitem>
- <para>The X coordinate of the upper-left corner of the source
- rectangle within the source layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcy</parameter></term>
- <listitem>
- <para>The Y coordinate of the upper-left corner of the source
- rectangle within the source layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcwidth</parameter></term>
- <listitem>
- <para>The width of the source rectangle within the source
- layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcheight</parameter></term>
- <listitem>
- <para>The height of the source rectangle within the source
- layer.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/curve.xml b/src/references/instructions/server/drawing/curve.xml
deleted file mode 100644
index ffc5c36..0000000
--- a/src/references/instructions/server/drawing/curve.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="curve-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>curve</title>
- <indexterm>
- <primary>curve</primary>
- </indexterm>
- <para>Adds the specified cubic bezier curve subpath.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer which should have the specified curve subpath
- added.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>cp1x</parameter></term>
- <listitem>
- <para>The X coordinate of the first control point of the
- curve.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>cp1y</parameter></term>
- <listitem>
- <para>The Y coordinate of the first control point of the
- curve.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>cp2x</parameter></term>
- <listitem>
- <para>The X coordinate of the second control point of the
- curve.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>cp2y</parameter></term>
- <listitem>
- <para>The Y coordinate of the second control point of the
- curve.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The X coordinate of the endpoint of the curve.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The Y coordinate of the endpoint of the curve.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/dispose.xml b/src/references/instructions/server/drawing/dispose.xml
deleted file mode 100644
index 956f69d..0000000
--- a/src/references/instructions/server/drawing/dispose.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="dispose-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>dispose</title>
-
- <indexterm>
- <primary>dispose</primary>
- </indexterm>
- <para>Removes the specified layer. The specified layer will be recreated as a
- new layer if it is referenced again.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer to remove.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/distort.xml b/src/references/instructions/server/drawing/distort.xml
deleted file mode 100644
index 6532823..0000000
--- a/src/references/instructions/server/drawing/distort.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="distort-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>distort</title>
-
- <indexterm>
- <primary>distort</primary>
- </indexterm>
- <para>Sets the given affine transformation matrix to the layer. Unlike
- transform, this operation is independent of any previously sent
- transformation matrix. This operation can be undone by setting the
- layer's transformation matrix to the identity matrix using
- distort</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer to distort.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>a</parameter></term>
- <listitem>
- <para>The matrix value in row 1, column 1.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>b</parameter></term>
- <listitem>
- <para>The matrix value in row 2, column 1.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>c</parameter></term>
- <listitem>
- <para>The matrix value in row 1, column 2.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>d</parameter></term>
- <listitem>
- <para>The matrix value in row 2, column 2.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>e</parameter></term>
- <listitem>
- <para>The matrix value in row 1, column 3.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>f</parameter></term>
- <listitem>
- <para>The matrix value in row 2, column 3.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/identity.xml b/src/references/instructions/server/drawing/identity.xml
deleted file mode 100644
index b1fceef..0000000
--- a/src/references/instructions/server/drawing/identity.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="identity-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>identity</title>
-
- <indexterm>
- <primary>identity</primary>
- </indexterm>
- <para>Resets the transform matrix of the specified layer to the identity
- matrix.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose transform matrix should be reset.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/lfill.xml b/src/references/instructions/server/drawing/lfill.xml
deleted file mode 100644
index 1e64dd1..0000000
--- a/src/references/instructions/server/drawing/lfill.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="lfill-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>lfill</title>
-
- <indexterm>
- <primary>lfill</primary>
- </indexterm>
- <para>Fills the current path with a tiled pattern of the image data from the
- specified layer. This instruction completes the current path. Future
- path instructions will begin a new path.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>mask</parameter></term>
- <listitem>
- <para>The channel mask to apply when filling the current path in
- the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose path should be filled.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srclayer</parameter></term>
- <listitem>
- <para>The layer to use as the pattern.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/line.xml b/src/references/instructions/server/drawing/line.xml
deleted file mode 100644
index 74f67d1..0000000
--- a/src/references/instructions/server/drawing/line.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="line-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>line</title>
-
- <indexterm>
- <primary>line</primary>
- </indexterm>
- <para>Adds the specified line subpath.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer which should have the specified line subpath
- added.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The X coordinate of the endpoint of the line.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The Y coordinate of the endpoint of the line.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/lstroke.xml b/src/references/instructions/server/drawing/lstroke.xml
deleted file mode 100644
index 0c16619..0000000
--- a/src/references/instructions/server/drawing/lstroke.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="lstroke-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>lstroke</title>
-
- <indexterm>
- <primary>lstroke</primary>
- </indexterm>
- <para>Strokes the current path with a tiled pattern of the image data from
- the specified layer. This instruction completes the current path. Future
- path instructions will begin a new path.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>mask</parameter></term>
- <listitem>
- <para>The channel mask to apply when filling the current path in
- the specified layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose path should be filled.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>cap</parameter></term>
- <listitem>
- <para>The index of the line cap style to use. This can be either
- butt (0), round (1), or square (2).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>join</parameter></term>
- <listitem>
- <para>The index of the line join style to use. This can be
- either bevel (0), miter (1), or round (2).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>thickness</parameter></term>
- <listitem>
- <para>The thickness of the stroke to draw, in pixels.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srclayer</parameter></term>
- <listitem>
- <para>The layer to use as the pattern.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/move.xml b/src/references/instructions/server/drawing/move.xml
deleted file mode 100644
index 833a4a1..0000000
--- a/src/references/instructions/server/drawing/move.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="move-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>move</title>
-
- <indexterm>
- <primary>move</primary>
- </indexterm>
- <para>Moves the given layer to the given location within the specified parent
- layer. This operation is applicable only to layers, and cannot be
- applied to buffers (layers with negative indices). Applying this
- operation to the default layer (layer 0) also has no effect.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer to move.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>parent</parameter></term>
- <listitem>
- <para>The layer that should be the parent of the given
- layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The X coordinate to move the layer to.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The Y coordinate to move the layer to.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>z</parameter></term>
- <listitem>
- <para>The relative Z-ordering of this layer. Layers with larger
- values will appear above layers with smaller values.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/pop.xml b/src/references/instructions/server/drawing/pop.xml
deleted file mode 100644
index 1169bfe..0000000
--- a/src/references/instructions/server/drawing/pop.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="pop-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>pop</title>
-
- <indexterm>
- <primary>pop</primary>
- </indexterm>
- <para>Restores the previous state of the specified layer from the stack. The
- state restored includes the transformation matrix and clipping
- path.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose state should be restored.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/push.xml b/src/references/instructions/server/drawing/push.xml
deleted file mode 100644
index 5fe2eda..0000000
--- a/src/references/instructions/server/drawing/push.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="push-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>push</title>
-
- <indexterm>
- <primary>push</primary>
- </indexterm>
- <para>Saves the current state of the specified layer to the stack. The state
- saved includes the current transformation matrix and clipping
- path.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose state should be saved.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/rect.xml b/src/references/instructions/server/drawing/rect.xml
deleted file mode 100644
index 40629c7..0000000
--- a/src/references/instructions/server/drawing/rect.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="rect-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>rect</title>
-
- <indexterm>
- <primary>rect</primary>
- </indexterm>
- <para>Adds a rectangular path to the specified layer.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>mask</parameter></term>
- <listitem>
- <para>The channel mask to apply when drawing the image
- data.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The destination layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The X coordinate of the upper-left corner of the rectangle
- to draw.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The Y coordinate of the upper-left corner of the rectangle
- to draw.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>width</parameter></term>
- <listitem>
- <para>The width of the rectangle to draw.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>height</parameter></term>
- <listitem>
- <para>The width of the rectangle to draw.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/reset.xml b/src/references/instructions/server/drawing/reset.xml
deleted file mode 100644
index fbccc0f..0000000
--- a/src/references/instructions/server/drawing/reset.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="reset-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>reset</title>
-
- <indexterm>
- <primary>reset</primary>
- </indexterm>
- <para>Resets the transformation and clip state of the layer.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose state should be reset.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/set.xml b/src/references/instructions/server/drawing/set.xml
deleted file mode 100644
index 9da5851..0000000
--- a/src/references/instructions/server/drawing/set.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="set-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>set</title>
-
- <indexterm>
- <primary>set</primary>
- </indexterm>
- <para>Sets the given client-side property to the specified value. Currently
- there is only one property: miter-limit, the maximum distance between
- the inner and outer points of a miter joint, proportional to stroke
- width (if miter-limit is set to 10.0, the default, then the maximum
- distance between the points of the joint is 10 times the stroke
- width).</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose property should be set.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>property</parameter></term>
- <listitem>
- <para>The name of the property to set.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>value</parameter></term>
- <listitem>
- <para>The value to set the given property to.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/shade.xml b/src/references/instructions/server/drawing/shade.xml
deleted file mode 100644
index aa64edd..0000000
--- a/src/references/instructions/server/drawing/shade.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="shade-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>shade</title>
-
- <indexterm>
- <primary>shade</primary>
- </indexterm>
- <para>Sets the opacity of the given layer.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer whose opacity should be set.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>opacity</parameter></term>
- <listitem>
- <para>The opacity of the layer, where 0 is completely
- transparent, and 255 is completely opaque.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/size.xml b/src/references/instructions/server/drawing/size.xml
deleted file mode 100644
index 8b939a9..0000000
--- a/src/references/instructions/server/drawing/size.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="size-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>size</title>
-
- <indexterm>
- <primary>size</primary>
- </indexterm>
- <para>Sets the size of the specified layer.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer to resize.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>width</parameter></term>
- <listitem>
- <para>The new width of the layer</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>height</parameter></term>
- <listitem>
- <para>The new height of the layer</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/start.xml b/src/references/instructions/server/drawing/start.xml
deleted file mode 100644
index a7bfc7f..0000000
--- a/src/references/instructions/server/drawing/start.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="start-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>start</title>
-
- <indexterm>
- <primary>start</primary>
- </indexterm>
- <para>Starts a new subpath at the specified point.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer which should start a new subpath.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The X coordinate of the first point of the new
- subpath.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The Y coordinate of the first point of the new
- subpath.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/transfer.xml b/src/references/instructions/server/drawing/transfer.xml
deleted file mode 100644
index b81e514..0000000
--- a/src/references/instructions/server/drawing/transfer.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="transfer-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>transfer</title>
-
- <indexterm>
- <primary>transfer</primary>
- </indexterm>
- <para>Transfers image data from the specified rectangle of the specified layer or buffer to a
- different location of another specified layer or buffer, using the specified transfer
- function. </para>
- <para>For a list of available functions, see the definition of
- <classname>guac_transfer_function</classname> within the <link
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://github.com/apache/guacamole-server/blob/master/src/libguac/guacamole/protocol-types.h"
- ><filename>guacamole/protocol-types.h</filename></link> header included with
- libguac.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>srclayer</parameter></term>
- <listitem>
- <para>The index of the layer to transfer image data from.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcx</parameter></term>
- <listitem>
- <para>The X coordinate of the upper-left corner of the source
- rectangle within the source layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcy</parameter></term>
- <listitem>
- <para>The Y coordinate of the upper-left corner of the source
- rectangle within the source layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcwidth</parameter></term>
- <listitem>
- <para>The width of the source rectangle within the source
- layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>srcheight</parameter></term>
- <listitem>
- <para>The height of the source rectangle within the source
- layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>function</parameter></term>
- <listitem>
- <para>The index of the transfer function to use.</para>
- <para>For a list of available functions, see the definition of
- <classname>guac_transfer_function</classname> within the <link
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xlink:href="https://github.com/apache/guacamole-server/blob/master/src/libguac/guacamole/protocol-types.h"
- ><filename>guacamole/protocol-types.h</filename></link> header included
- with libguac.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>dstlayer</parameter></term>
- <listitem>
- <para>The index of the layer to draw the image data to.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>dstx</parameter></term>
- <listitem>
- <para>The X coordinate of the upper-left corner of the
- destination within the destination layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>dsty</parameter></term>
- <listitem>
- <para>The Y coordinate of the upper-left corner of the
- destination within the destination layer.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/drawing/transform.xml b/src/references/instructions/server/drawing/transform.xml
deleted file mode 100644
index 15a66d4..0000000
--- a/src/references/instructions/server/drawing/transform.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="transform-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>transform</title>
-
- <indexterm>
- <primary>transform</primary>
- </indexterm>
- <para>Applies the specified transformation matrix to future operations.
- Unlike distort, this operation is dependent on any previously sent
- transformation matrices, and only affects future operations. This
- operation can be undone by setting the layer's transformation matrix to
- the identity matrix using identity, but image data already drawn will
- not be affected.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The layer to apply the given transformation matrix
- to.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>a</parameter></term>
- <listitem>
- <para>The matrix value in row 1, column 1.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>b</parameter></term>
- <listitem>
- <para>The matrix value in row 2, column 1.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>c</parameter></term>
- <listitem>
- <para>The matrix value in row 1, column 2.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>d</parameter></term>
- <listitem>
- <para>The matrix value in row 2, column 2.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>e</parameter></term>
- <listitem>
- <para>The matrix value in row 1, column 3.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>f</parameter></term>
- <listitem>
- <para>The matrix value in row 2, column 3.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/handshake/args.xml b/src/references/instructions/server/handshake/args.xml
deleted file mode 100644
index 0e27698..0000000
--- a/src/references/instructions/server/handshake/args.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="args-instruction"
- xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
-
-
- <title>args</title>
- <para>Reports the expected format of the argument list for the protocol
- requested by the client. This message can be sent by the server during
- the handshake phase only.</para>
- <para>The first parameter of this instruction will be the protocol version
- supported by the server. This is used to negotiate protocol
- compatibility between the client and the server, with the highest
- supported protocol by both sides being chosen. Versions of Guacamole
- prior to 1.1.0 do not support protocol version negotiation, and will
- silently ignore this instruction.</para>
- <para>The remaining parameters of the args instruction are the names of all
- connection parameters accepted by the server for the protocol selected
- by the client, in order. The client's responding connect instruction
- must contain the values of each of these parameters in the same order.
- </para>
-
-</section>
diff --git a/src/references/instructions/server/object/body.xml b/src/references/instructions/server/object/body.xml
deleted file mode 100644
index 21de3e2..0000000
--- a/src/references/instructions/server/object/body.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="body-object-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>body</title>
- <indexterm>
- <primary>body</primary>
- </indexterm>
- <para>Allocates a new stream, associating it with the name of a stream previously requested by a
- get instruction. The contents of the stream will be sent later with blob instructions. The
- full size of the stream need not be known ahead of time.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>object</parameter></term>
- <listitem>
- <para>The index of the object associated with this stream.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mimetype</parameter></term>
- <listitem>
- <para>The mimetype of the data being sent.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>name</parameter></term>
- <listitem>
- <para>The name of the stream associated with the object.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/object/filesystem.xml b/src/references/instructions/server/object/filesystem.xml
deleted file mode 100644
index 98814d8..0000000
--- a/src/references/instructions/server/object/filesystem.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="filesystem-object-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>filesystem</title>
- <indexterm>
- <primary>filesystem</primary>
- </indexterm>
- <para>Allocates a new object, associating it with the given arbitrary filesystem metadata. The
- contents of files and directories within the filesystem will later be sent along streams
- requested with get instructions or created with put instructions.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>object</parameter></term>
- <listitem>
- <para>The index of the object to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>name</parameter></term>
- <listitem>
- <para>The name of the filesystem.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/object/get.xml b/src/references/instructions/server/object/get.xml
deleted file mode 100644
index b1307c0..0000000
--- a/src/references/instructions/server/object/get.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="get-object-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>get</title>
- <indexterm>
- <primary>get</primary>
- </indexterm>
- <para>Requests that a new stream be created, providing read access to the object stream having
- the given name. The requested stream will be created, in response, with a body
- instruction.</para>
- <para>Stream names are arbitrary and dictated by the object from which they are requested, with
- the exception of the root stream of the object itself, which has the reserved name
- "<constant>/</constant>". The root stream of the object has the mimetype
- "<constant>application/vnd.glyptodon.guacamole.stream-index+json</constant>", and
- provides a simple JSON map of available stream names to their corresponding mimetypes. If
- the object contains a hierarchy of streams, some of these streams may also be
- "<constant>application/vnd.glyptodon.guacamole.stream-index+json</constant>".</para>
- <para>For example, the ultimate content of the body stream provided in response to a get request
- for the root stream of an object containing two text streams, "A" and "B", would be the
- following:</para>
- <informalexample>
- <programlisting>{
- "A" : "text/plain",
- "B" : "text/plain"
-}</programlisting>
- </informalexample>
- <variablelist>
- <varlistentry>
- <term><parameter>object</parameter></term>
- <listitem>
- <para>The index of the object to request a stream from.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>name</parameter></term>
- <listitem>
- <para>The name of the stream being requested from the given object.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/object/put.xml b/src/references/instructions/server/object/put.xml
deleted file mode 100644
index db23796..0000000
--- a/src/references/instructions/server/object/put.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="put-object-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>put</title>
- <indexterm>
- <primary>put</primary>
- </indexterm>
- <para>Allocates a new stream, associating it with the given arbitrary object and stream name.
- The contents of the stream will later be sent with blob instructions.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>object</parameter></term>
- <listitem>
- <para>The index of the object associated with this stream.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mimetype</parameter></term>
- <listitem>
- <para>The mimetype of the data being sent.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>name</parameter></term>
- <listitem>
- <para>The name of the stream within the given object to which data is being
- sent.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/object/undefine.xml b/src/references/instructions/server/object/undefine.xml
deleted file mode 100644
index 1f7a367..0000000
--- a/src/references/instructions/server/object/undefine.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="undefine-object-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>undefine</title>
- <indexterm>
- <primary>undefine</primary>
- </indexterm>
- <para>Undefines an existing object, allowing its index to be reused by another future object.
- The resource associated with the original object may or may not continue to exist - it
- simply no longer has an associated object.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>object</parameter></term>
- <listitem>
- <para>The index of the object to undefine.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/ack.xml b/src/references/instructions/server/stream/ack.xml
deleted file mode 100644
index c15d141..0000000
--- a/src/references/instructions/server/stream/ack.xml
+++ /dev/null
@@ -1,226 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="ack-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>ack</title>
- <indexterm>
- <primary>ack</primary>
- </indexterm>
- <para>The ack instruction acknowledges a received data blob, providing a status code and message
- indicating whether the operation associated with the blob succeeded or failed. A status code
- other than <constant>SUCCESS</constant> implicitly ends the stream.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream the corresponding blob was received on.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>message</parameter></term>
- <listitem>
- <para>A human-readable error message. This typically is not exposed within any user
- interface, and mainly helps with debugging.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>status</parameter></term>
- <listitem>
- <para>The Guacamole status code denoting success or failure.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- <section xml:id="status-codes">
- <title>Status codes</title>
- <para>Several Guacamole instructions, and various other internals of the Guacamole core, use
- a common set of numeric status codes. These codes denote success or failure of
- operations, and can be rendered by user interfaces in a human-readable
- way.<informaltable frame="all">
- <tgroup cols="3">
- <colspec colname="c1" colnum="1" colwidth="1.25*"/>
- <colspec colname="c2" colnum="2" colwidth="3.25*"/>
- <colspec colname="c3" colnum="3" colwidth="9*"/>
- <thead>
- <row>
- <entry>Code</entry>
- <entry>Name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>0</entry>
- <entry><constant>SUCCESS</constant></entry>
- <entry>
- <para>The operation succeeded. No error.</para>
- </entry>
- </row>
- <row>
- <entry>256</entry>
- <entry><constant>UNSUPPORTED</constant></entry>
- <entry>
- <para>The requested operation is unsupported.</para>
- </entry>
- </row>
- <row>
- <entry>512</entry>
- <entry><constant>SERVER_ERROR</constant></entry>
- <entry>
- <para>An internal error occurred, and the operation could not be
- performed.</para>
- </entry>
- </row>
- <row>
- <entry>513</entry>
- <entry><constant>SERVER_BUSY</constant></entry>
- <entry>
- <para>The operation could not be performed because the server is
- busy.</para>
- </entry>
- </row>
- <row>
- <entry>514</entry>
- <entry><constant>UPSTREAM_TIMEOUT</constant></entry>
- <entry>
- <para>The upstream server is not responding. In most cases, the
- upstream server is the remote desktop server.</para>
- </entry>
- </row>
- <row>
- <entry>515</entry>
- <entry><constant>UPSTREAM_ERROR</constant></entry>
- <entry>
- <para>The upstream server encountered an error. In most cases, the
- upstream server is the remote desktop server.</para>
- </entry>
- </row>
- <row>
- <entry>516</entry>
- <entry><constant>RESOURCE_NOT_FOUND</constant></entry>
- <entry>
- <para>An associated resource, such as a file or stream, could not be
- found, and thus the operation failed.</para>
- </entry>
- </row>
- <row>
- <entry>517</entry>
- <entry><constant>RESOURCE_CONFLICT</constant></entry>
- <entry>
- <para>A resource is already in use or locked, preventing the
- requested operation.</para>
- </entry>
- </row>
- <row>
- <entry>518</entry>
- <entry><constant>RESOURCE_CLOSED</constant></entry>
- <entry>
- <para>The requested operation cannot continue because the associated
- resource has been closed.</para>
- </entry>
- </row>
- <row>
- <entry>519</entry>
- <entry><constant>UPSTREAM_NOT_FOUND</constant></entry>
- <entry>
- <para>The upstream server does not appear to exist, or cannot be
- reached over the network. In most cases, the upstream server is
- the remote desktop server.</para>
- </entry>
- </row>
- <row>
- <entry>520</entry>
- <entry><constant>UPSTREAM_UNAVAILABLE</constant></entry>
- <entry>
- <para>The upstream server is refusing to service connections. In
- most cases, the upstream server is the remote desktop
- server.</para>
- </entry>
- </row>
- <row>
- <entry>521</entry>
- <entry><constant>SESSION_CONFLICT</constant></entry>
- <entry>
- <para>The session within the upstream server has ended because it
- conflicts with another session. In most cases, the upstream
- server is the remote desktop server.</para>
- </entry>
- </row>
- <row>
- <entry>522</entry>
- <entry><constant>SESSION_TIMEOUT</constant></entry>
- <entry>
- <para>The session within the upstream server has ended because it
- appeared to be inactive. In most cases, the upstream server is
- the remote desktop server.</para>
- </entry>
- </row>
- <row>
- <entry>523</entry>
- <entry><constant>SESSION_CLOSED</constant></entry>
- <entry>
- <para>The session within the upstream server has been forcibly
- closed. In most cases, the upstream server is the remote desktop
- server.</para>
- </entry>
- </row>
- <row>
- <entry>768</entry>
- <entry><constant>CLIENT_BAD_REQUEST</constant></entry>
- <entry>
- <para>The parameters of the request are illegal or otherwise
- invalid.</para>
- </entry>
- </row>
- <row>
- <entry>769</entry>
- <entry><constant>CLIENT_UNAUTHORIZED</constant></entry>
- <entry>
- <para>Permission was denied, because the user is not logged in. Note
- that the user may be logged into Guacamole, but still not logged
- in with respect to the remote desktop server.</para>
- </entry>
- </row>
- <row>
- <entry>771</entry>
- <entry><constant>CLIENT_FORBIDDEN</constant></entry>
- <entry>
- <para>Permission was denied, and logging in will not solve the
- problem.</para>
- </entry>
- </row>
- <row>
- <entry>776</entry>
- <entry><constant>CLIENT_TIMEOUT</constant></entry>
- <entry>
- <para>The client (usually the user of Guacamole or their browser) is
- taking too long to respond.</para>
- </entry>
- </row>
- <row>
- <entry>781</entry>
- <entry><constant>CLIENT_OVERRUN</constant></entry>
- <entry>
- <para>The client has sent more data than the protocol allows.</para>
- </entry>
- </row>
- <row>
- <entry>783</entry>
- <entry><constant>CLIENT_BAD_TYPE</constant></entry>
- <entry>
- <para>The client has sent data of an unexpected or illegal
- type.</para>
- </entry>
- </row>
- <row>
- <entry>797</entry>
- <entry><constant>CLIENT_TOO_MANY</constant></entry>
- <entry>
- <para>The client is already using too many resources. Existing
- resources must be freed before further requests are
- allowed.</para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable></para>
- </section>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/argv.xml b/src/references/instructions/server/stream/argv.xml
deleted file mode 100644
index 8ec6df3..0000000
--- a/src/references/instructions/server/stream/argv.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="argv-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>argv</title>
- <indexterm>
- <primary>argv</primary>
- </indexterm>
- <para>Allocates a new stream, associating it with the given argument (connection parameter)
- metadata. The relevant connection parameter data will later be sent along the stream with
- blob instructions. If sent by the client, this data will be the desired new value of the
- connection parameter being changed, and will be applied if the server supports changing that
- connection parameter while the connection is active. If sent by the server, this data will
- be the current value of a connection parameter being exposed to the client.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mimetype</parameter></term>
- <listitem>
- <para>The mimetype of the connection parameter being sent. In most cases, this will
- be "text/plain".</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>name</parameter></term>
- <listitem>
- <para>The name of the connection parameter whose value is being sent.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/audio.xml b/src/references/instructions/server/stream/audio.xml
deleted file mode 100644
index 4bba450..0000000
--- a/src/references/instructions/server/stream/audio.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="audio-stream-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>audio</title>
- <indexterm>
- <primary>audio</primary>
- </indexterm>
- <para>Allocates a new stream, associating it with the given audio metadata. Audio data will
- later be sent along the stream with blob instructions. The mimetype given must be a mimetype
- previously specified by the client during the handshake procedure. Playback will begin
- immediately and will continue as long as blobs are received along the stream.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mimetype</parameter></term>
- <listitem>
- <para>The mimetype of the audio data being sent.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/blob.xml b/src/references/instructions/server/stream/blob.xml
deleted file mode 100644
index 4e6d676..0000000
--- a/src/references/instructions/server/stream/blob.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="blob-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>blob</title>
- <indexterm>
- <primary>blob</primary>
- </indexterm>
- <para>Sends a blob of data along the given stream. This blob of data is arbitrary,
- base64-encoded data, and only has meaning to the Guacamole client or server through the
- metadata assigned to the stream when the stream was allocated.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream along which the given data should be sent.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter></term>
- <listitem>
- <para>The base64-encoded data to send.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/clipboard.xml b/src/references/instructions/server/stream/clipboard.xml
deleted file mode 100644
index 09ce151..0000000
--- a/src/references/instructions/server/stream/clipboard.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="clipboard-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>clipboard</title>
- <indexterm>
- <primary>clipboard</primary>
- </indexterm>
- <para>Allocates a new stream, associating it with the given clipboard metadata. The clipboard
- data will later be sent along the stream with blob instructions. If sent by the client, this
- data will be the contents of the client-side clipboard. If sent by the server, this data
- will be the contents of the clipboard within the remote desktop.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mimetype</parameter></term>
- <listitem>
- <para>The mimetype of the clipboard data being sent. In most cases, this will be
- "text/plain".</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/end.xml b/src/references/instructions/server/stream/end.xml
deleted file mode 100644
index 71cdbe0..0000000
--- a/src/references/instructions/server/stream/end.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="end-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>end</title>
- <indexterm>
- <primary>end</primary>
- </indexterm>
- <para>The end instruction terminates an open stream, freeing any client-side or server-side
- resources. Data sent to a terminated stream will be ignored. Terminating a stream with the
- end instruction only denotes the end of the stream and does not imply an error.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream the corresponding blob was received on.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/file.xml b/src/references/instructions/server/stream/file.xml
deleted file mode 100644
index 0078e11..0000000
--- a/src/references/instructions/server/stream/file.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="file-stream-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>file</title>
- <indexterm>
- <primary>file</primary>
- </indexterm>
- <para>Allocates a new stream, associating it with the given arbitrary file metadata. The
- contents of the file will later be sent along the stream with blob instructions. The full
- size of the file need not be known ahead of time.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mimetype</parameter></term>
- <listitem>
- <para>The mimetype of the file being sent.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>filename</parameter></term>
- <listitem>
- <para>The name of the file, as it would be saved on a filesystem.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/img.xml b/src/references/instructions/server/stream/img.xml
deleted file mode 100644
index ef39cb3..0000000
--- a/src/references/instructions/server/stream/img.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="img-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>img</title>
- <indexterm>
- <primary>img</primary>
- </indexterm>
- <para>Allocates a new stream, associating it with the metadata of an image update, including the
- image type, the destination layer, and destination coordinates. The contents of the image
- will later be sent along the stream with blob instructions. The full size of the image need
- not be known ahead of time.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mimetype</parameter></term>
- <listitem>
- <para>The mimetype of the image being sent.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mask</parameter></term>
- <listitem>
- <para>The channel mask to apply when drawing the image data.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The destination layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>x</parameter></term>
- <listitem>
- <para>The X coordinate of the upper-left corner of the destination within the
- destination layer.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>y</parameter></term>
- <listitem>
- <para>The Y coordinate of the upper-left corner of the destination within the
- destination layer.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/nest.xml b/src/references/instructions/server/stream/nest.xml
deleted file mode 100644
index 50119f9..0000000
--- a/src/references/instructions/server/stream/nest.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="nest-stream-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>nest</title>
- <indexterm>
- <primary>nest</primary>
- </indexterm>
- <important>
- <para><emphasis>The <function>nest</function> instruction has been
- deprecated.</emphasis></para>
- <para>The <function>nest</function> instruction is no longer necessary, having been replaced
- by other streaming instructions (such as <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="blob-instruction"
- ><function>blob</function></link>, <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="ack-instruction"
- ><function>ack</function></link>, and <link
- xmlns:xlink="http://www.w3.org/1999/xlink" linkend="end-instruction"
- ><function>end</function></link>). Code using the <function>nest</function>
- instruction should instead write instructions directly without wrapping those
- instructions within <function>nest</function>.</para>
- </important>
- <para>Encodes part of one or more instructions within a single instruction,
- associating that packet of data with a stream index. Future nest
- instructions with the same stream index will append their data to the
- same logical stream on the client side. Once nested data is received on
- the client side, the client immediately executes any completed
- instructions within the associated stream, in order.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>index</parameter></term>
- <listitem>
- <para>The index of the stream this data should be appended to.
- This index is completely arbitrary, and denotes only how
- nested data should be reassembled.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>data</parameter></term>
- <listitem>
- <para>The protocol data, containing part of one or more
- instructions.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/pipe.xml b/src/references/instructions/server/stream/pipe.xml
deleted file mode 100644
index affb729..0000000
--- a/src/references/instructions/server/stream/pipe.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<section xml:id="pipe-instruction" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>pipe</title>
- <indexterm>
- <primary>pipe</primary>
- </indexterm>
- <para>Allocates a new stream, associating it with the given arbitrary named pipe metadata. The
- contents of the pipe will later be sent along the stream with blob instructions. Pipes in
- the Guacamole protocol are unidirectional, named pipes, very similar to a UNIX FIFO or pipe.
- It is up to client-side code to handle pipe data appropriately, likely based upon the name
- of the pipe, which is arbitrary. Pipes may be opened by either the client or the
- server.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mimetype</parameter></term>
- <listitem>
- <para>The mimetype of the data being sent along the pipe.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>name</parameter></term>
- <listitem>
- <para>The arbitrary name of the pipe, which may have special meaning to client-side
- code.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/instructions/server/stream/video.xml b/src/references/instructions/server/stream/video.xml
deleted file mode 100644
index 022fb11..0000000
--- a/src/references/instructions/server/stream/video.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<section xml:id="video-stream-instruction" xmlns="http://docbook.org/ns/docbook"
- version="5.0" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>video</title>
- <indexterm>
- <primary>video</primary>
- </indexterm>
- <para>Allocates a new stream, associating it with the given video metadata. Video data will
- later be sent along the stream with blob instructions. The mimetype given must be a mimetype
- previously specified by the client during the handshake procedure. Playback will begin
- immediately and will continue as long as blobs are received along the stream.</para>
- <variablelist>
- <varlistentry>
- <term><parameter>stream</parameter></term>
- <listitem>
- <para>The index of the stream to allocate.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>layer</parameter></term>
- <listitem>
- <para>The index of the layer to stream the video data into. The effect of other
- drawing operations on this layer during playback is undefined, as the client
- codec implementation may leverage any rendering mechanism it sees fit, including
- hardware decoding.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>mimetype</parameter></term>
- <listitem>
- <para>The mimetype of the video data being sent.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-</section>
\ No newline at end of file
diff --git a/src/references/protocol.xml b/src/references/protocol.xml
deleted file mode 100644
index 0c98df5..0000000
--- a/src/references/protocol.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<appendix xml:id="protocol-reference" xmlns="http://docbook.org/ns/docbook" version="5.0"
- xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude">
- <title>Guacamole protocol reference</title>
- <indexterm>
- <primary>Guacamole protocol</primary>
- </indexterm>
- <indexterm>
- <primary>protocol reference</primary>
- </indexterm>
- <indexterm>
- <primary>instructions</primary>
- </indexterm>
- <section xml:id="drawing-instructions">
- <title>Drawing instructions</title>
- <indexterm>
- <primary>drawing instructions</primary>
- </indexterm>
- <indexterm>
- <primary>instructions</primary>
- <secondary>drawing</secondary>
- </indexterm>
- <indexterm>
- <primary>server instructions</primary>
- <secondary>drawing</secondary>
- </indexterm>
- <xi:include href="instructions/server/drawing/arc.xml"/>
- <xi:include href="instructions/server/drawing/cfill.xml"/>
- <xi:include href="instructions/server/drawing/clip.xml"/>
- <xi:include href="instructions/server/drawing/close.xml"/>
- <xi:include href="instructions/server/drawing/copy.xml"/>
- <xi:include href="instructions/server/drawing/cstroke.xml"/>
- <xi:include href="instructions/server/drawing/cursor.xml"/>
- <xi:include href="instructions/server/drawing/curve.xml"/>
- <xi:include href="instructions/server/drawing/dispose.xml"/>
- <xi:include href="instructions/server/drawing/distort.xml"/>
- <xi:include href="instructions/server/drawing/identity.xml"/>
- <xi:include href="instructions/server/drawing/lfill.xml"/>
- <xi:include href="instructions/server/drawing/line.xml"/>
- <xi:include href="instructions/server/drawing/lstroke.xml"/>
- <xi:include href="instructions/server/drawing/move.xml"/>
- <xi:include href="instructions/server/drawing/pop.xml"/>
- <xi:include href="instructions/server/drawing/push.xml"/>
- <xi:include href="instructions/server/drawing/rect.xml"/>
- <xi:include href="instructions/server/drawing/reset.xml"/>
- <xi:include href="instructions/server/drawing/set.xml"/>
- <xi:include href="instructions/server/drawing/shade.xml"/>
- <xi:include href="instructions/server/drawing/size.xml"/>
- <xi:include href="instructions/server/drawing/start.xml"/>
- <xi:include href="instructions/server/drawing/transfer.xml"/>
- <xi:include href="instructions/server/drawing/transform.xml"/>
- </section>
- <section xml:id="streaming-instructions">
- <title>Streaming instructions</title>
- <xi:include href="instructions/server/stream/ack.xml"/>
- <xi:include href="instructions/server/stream/argv.xml"/>
- <xi:include href="instructions/server/stream/audio.xml"/>
- <xi:include href="instructions/server/stream/blob.xml"/>
- <xi:include href="instructions/server/stream/clipboard.xml"/>
- <xi:include href="instructions/server/stream/end.xml"/>
- <xi:include href="instructions/server/stream/file.xml"/>
- <xi:include href="instructions/server/stream/img.xml"/>
- <xi:include href="instructions/server/stream/nest.xml"/>
- <xi:include href="instructions/server/stream/pipe.xml"/>
- <xi:include href="instructions/server/stream/video.xml"/>
- </section>
- <section xml:id="object-instructions">
- <title>Object instructions</title>
- <xi:include href="instructions/server/object/body.xml"/>
- <xi:include href="instructions/server/object/filesystem.xml"/>
- <xi:include href="instructions/server/object/get.xml"/>
- <xi:include href="instructions/server/object/put.xml"/>
- <xi:include href="instructions/server/object/undefine.xml"/>
- </section>
- <section xml:id="client-handshake-instructions">
- <title>Client handshake instructions</title>
- <xi:include href="instructions/client/handshake/audio.xml"/>
- <xi:include href="instructions/client/handshake/connect.xml"/>
- <xi:include href="instructions/client/handshake/image.xml"/>
- <xi:include href="instructions/client/handshake/select.xml"/>
- <xi:include href="instructions/client/handshake/size.xml"/>
- <xi:include href="instructions/client/handshake/timezone.xml"/>
- <xi:include href="instructions/client/handshake/video.xml"/>
- </section>
- <section xml:id="server-handshake-instructions">
- <title>Server handshake instructions</title>
- <xi:include href="instructions/server/handshake/args.xml"/>
- </section>
- <section xml:id="client-control-instructions">
- <title>Client control instructions</title>
- <indexterm>
- <primary>control instructions</primary>
- </indexterm>
- <indexterm>
- <primary>instructions</primary>
- <secondary>control</secondary>
- </indexterm>
- <indexterm>
- <primary>client instructions</primary>
- <secondary>control</secondary>
- </indexterm>
- <xi:include href="instructions/client/control/disconnect.xml"/>
- <xi:include href="instructions/client/control/nop.xml"/>
- <xi:include href="instructions/client/control/sync.xml"/>
- </section>
- <section xml:id="server-control-instructions">
- <title>Server control instructions</title>
- <indexterm>
- <primary>server instructions</primary>
- <secondary>control</secondary>
- </indexterm>
- <xi:include href="instructions/server/control/disconnect.xml"/>
- <xi:include href="instructions/server/control/error.xml"/>
- <xi:include href="instructions/server/control/log.xml"/>
- <xi:include href="instructions/server/control/mouse.xml"/>
- <xi:include href="instructions/server/control/nop.xml"/>
- <xi:include href="instructions/server/control/ready.xml"/>
- <xi:include href="instructions/server/control/sync.xml"/>
- </section>
- <section xml:id="client-events">
- <title>Client events</title>
- <indexterm>
- <primary>events</primary>
- </indexterm>
- <indexterm>
- <primary>instructions</primary>
- <secondary>events</secondary>
- </indexterm>
- <indexterm>
- <primary>client instructions</primary>
- <secondary>events</secondary>
- </indexterm>
- <xi:include href="instructions/client/event/key.xml"/>
- <xi:include href="instructions/client/event/mouse.xml"/>
- <xi:include href="instructions/client/event/size.xml"/>
- </section>
-</appendix>
diff --git a/src/reverse-proxy.md b/src/reverse-proxy.md
new file mode 100644
index 0000000..704e4f3
--- /dev/null
+++ b/src/reverse-proxy.md
@@ -0,0 +1,427 @@
+Proxying Guacamole
+==================
+
+Like most web applications, Guacamole can be placed behind a reverse proxy. For
+production deployments of Guacamole, this is *highly recommended*. It provides
+flexibility and, if your proxy is properly configured for SSL, encryption.
+
+Proxying isolates privileged operations within native applications that can
+safely drop those privileges when no longer needed, using Java only for
+unprivileged tasks. On Linux and UNIX systems, a process must be running with
+root privileges to listen on any port under 1024, including the standard HTTP
+and HTTPS ports (80 and 443 respectively). If the servlet container instead
+listens on a higher port, such as the default port 8080, it can run as a
+reduced-privilege user, allowing the reverse proxy to bear the burden of root
+privileges. As a native application, the reverse proxy can make system calls to
+safely drop root privileges once the port is open; a Java application like
+Tomcat cannot do this.
+
+(preparing-servlet-container)=
+
+Preparing your servlet container
+--------------------------------
+
+Your servlet container is most likely already configured to listen for HTTP
+connections on port 8080 as this is the default. If this is the case, and you
+can already access Guacamole over port 8080 from a web browser, you need not
+make any further changes to its configuration.
+
+If you *have* changed this, perhaps with the intent of proxying Guacamole over
+AJP, *change it back*. Using Guacamole over AJP is unsupported as it is known
+to cause problems, namely:
+
+1. WebSocket will not work over AJP, forcing Guacamole to fallback to HTTP,
+ possibly resulting in reduced performance.
+
+2. Apache 2.4.3 and older does not support the HTTP PATCH method over AJP,
+ preventing the Guacamole management interface from functioning properly.
+
+The connector entry within `conf/server.xml` should look like this:
+
+```xml
+<Connector port="8080" protocol="HTTP/1.1"
+ connectionTimeout="20000"
+ URIEncoding="UTF-8"
+ redirectPort="8443" />
+```
+
+Be sure to specify the `URIEncoding="UTF-8"` attribute as above to ensure that
+connection names, user names, etc. are properly received by the web
+application. If you will be creating connections that have Cyrillic, Chinese,
+Japanese, or other non-Latin characters in their names or parameter values,
+this attribute is required.
+
+(tomcat-remote-ip)=
+
+### Setting up the Remote IP Valve
+
+By default, when Tomcat is behind a reverse proxy, the remote IP address of the
+client that it sees is that of the proxy rather than the original client. In
+order to allow applications hosted within Tomcat, like Guacamole, to see the
+actual IP address of the client, you have to configure both the reverse proxy
+and Tomcat.
+
+Because the remote IP address in Guacamole is used for auditing of user logins
+and connections and could potentially be used for authentication, it is
+important that you are either in direct control of the proxy server or you
+explicitly trust it. Passing the remote IP address is done using the
+`X-Forwarded-For` header, and, as with most HTTP headers, attackers can attempt
+to spoof this header in order to manipulate the behavior of the web server,
+gain unauthorized access to the system, or attempt to disguise the host or IP
+address they are coming from.
+
+One final caveat: This may not work as expected if there are other upstream
+proxy servers between your reverse proxy and the clients access Guacamole.
+Other proxies or firewalls can mask the IP address of the client, and if the
+configuration of those is not within your control you may end up with multiple
+clients appearing to come from the same IP address or host. Make sure you take
+this into account when configuring the system and looking at the data provided.
+
+Configuring Tomcat to pass through the remote IP address provided by the
+reverse proxy in the `X-Forwarded-For` header requires the configuration of
+what Tomcat calls a Valve. In this case, it is the
+[`RemoteIpValve`](https://tomcat.apache.org/tomcat-8.5-doc/config/valve.html#Remote_IP_Valve)
+and is configured in the `conf/server.xml` file, in the `<Host>` section:
+
+```xml
+<Valve className="org.apache.catalina.valves.RemoteIpValve"
+ internalProxies="127.0.0.1"
+ remoteIpHeader="x-forwarded-for"
+ remoteIpProxiesHeader="x-forwarded-by"
+ protocolHeader="x-forwarded-proto" />
+```
+
+The `internalProxies` value should be set to the IP address or addresses of any
+and all reverse proxy servers that will be accessing this Tomcat instance
+directly. Often it is run on the same system that runs Tomcat, but in other
+cases (for example, when running Docker), it may be on a different
+system/container and may need to be set to the actual IP address of the reverse
+proxy system. Only proxy servers listed in the `internalProxies` or
+`trustedProxies` parameters will be allowed to manipulate the remote IP address
+information. The other parameters in this configuration line allow you to
+control which headers coming from the proxy server(s) are used for various
+remote host information. They are as follows:
+
+`remoteIpHeader`
+: The header that is queried to learn the client IP address of the client
+ that originated the request. The standard value is `X-Forwarded-For`, but
+ can be configured to any header you like. The IP address in this header
+ will be available to Java applications in the `request.getRemoteAddr()`
+ method.
+
+`remoteIpProxiesHeader`
+: The header that is queried to learn the IP address of the proxy server
+ that forwarded the request. The default value is `X-Forwarded-By`, but can
+ be configured to any header that fits your environment. This value will
+ only be allowed by the valve if the proxy used is listed in the
+ `trustedProxies` parameter. Otherwise this header will not be available.
+
+`protocolHeader`
+: The header that is queried to determine the protocol that the client used
+ to connect to the service. The default value is `X-Forwarded-Proto`, but
+ can be configured to fit your environment.
+
+In addition to configuring Tomcat to properly handle these headers, you also
+may need to configure your reverse proxy appropriately to send the headers. You
+can find instructions for this in [](nginx) - the Apache web server passes it
+through by default.
+
+(nginx)=
+
+Nginx
+-----
+
+Nginx can be used as a reverse proxy, and supports WebSocket out-of-the-box
+[since version 1.3](http://nginx.com/blog/websocket-nginx/). Both Apache and
+Nginx require some additional configuration for proxying of WebSocket to work
+properly.
+
+(proxying-with-nginx)=
+
+### Proxying Guacamole
+
+Nginx does support WebSocket for proxying, but requires that the "Connection"
+and "Upgrade" HTTP headers are set explicitly due to the nature of the
+WebSocket protocol. From the Nginx documentation:
+
+> NGINX supports WebSocket by allowing a tunnel to be set up between a client
+> and a back-end server. For NGINX to send the Upgrade request from the client
+> to the back-end server, Upgrade and Connection headers must be set
+> explicitly. ...
+
+The proxy configuration belongs within a dedicated
+[`location`](http://nginx.org/en/docs/http/ngx_http_core_module.html#location>)
+block, declaring the backend hosting Guacamole and explicitly specifying the
+"`Connection`" and "`Upgrade`" headers mentioned earlier:
+
+```nginx
+location /guacamole/ {
+ proxy_pass http://HOSTNAME:8080;
+ proxy_buffering off;
+ proxy_http_version 1.1;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $http_connection;
+ access_log off;
+}
+```
+
+Here, `HOSTNAME` is the hostname or IP address of the machine hosting your
+servlet container, and 8080 is the port that servlet container is configured to
+use. You will need to replace these values with the correct values for your
+server.
+
+Related to the `RemoteIpValve` configuration for tomcat, documented in
+[Setting up the Remote IP Valve](tomcat-remote-ip), the `proxy_set_header
+X-Forwarded-For $proxy_add_x_forwarded_for;` line is important if you want the
+`X-Forwarded-For` header to be passed through to the web application server and
+available to applications running inside it.
+
+:::{important}
+*Do not forget to specify "`proxy_buffering off`".*
+
+Most proxies, including Nginx, will buffer all data sent over the connection,
+waiting until the connection is closed before sending that data to the client.
+As Guacamole's HTTP tunnel relies on streaming data to the client over an open
+connection, excessive buffering will effectively block Guacamole connections,
+rendering Guacamole useless.
+
+*If the option "`proxy_buffering off`" is not specified, Guacamole may not
+work*.
+:::
+
+(changing-path-with-nginx)=
+
+### Changing the path
+
+If you wish to serve Guacamole through Nginx under a path other than
+`/guacamole/`, the easiest method is to simply rename the `.war` file. For
+example, if intending to server Guacamole at `/new-path/`, you would:
+
+1. Rename `guacamole.war` to `new-path.war`.
+
+2. Update the path within the Nginx configuration to reflect the new
+ path:
+
+ :::{code-block} nginx
+ :emphasize-lines: 1
+ location /new-path/ {
+ proxy_pass http://HOSTNAME:8080;
+ proxy_buffering off;
+ proxy_http_version 1.1;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $http_connection;
+ access_log off;
+ }
+ :::
+
+
+Alternatively, the configuration can be altered slightly to handle requests at
+a different location externally while still serving internal requests at
+`/guacamole/`:
+
+:::{code-block} nginx
+:emphasize-lines: 1-2
+location /new-path/ {
+ proxy_pass http://HOSTNAME:8080/guacamole/;
+ proxy_buffering off;
+ proxy_http_version 1.1;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $http_connection;
+ access_log off;
+}
+:::
+
+(nginx-file-upload-size)=
+
+### Adjusting file upload limits
+
+When proxying Guacamole through Nginx, you may run into issues with the default
+limitations that Nginx places on file uploads (1MB). The errors you receive can
+be non-intuitive (permission denied, for example), but may be indicative of
+these limits. The `client_max_body_size` parameter can be set within the
+`location` block to configure the maximum file upload size:
+
+:::{code-block} nginx
+:emphasize-lines: 8
+location /guacamole/ {
+ proxy_pass http://HOSTNAME:8080;
+ proxy_buffering off;
+ proxy_http_version 1.1;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $http_connection;
+ client_max_body_size 1g;
+ access_log off;
+}
+:::
+
+(apache)=
+
+Apache and mod_proxy
+--------------------
+
+Apache supports reverse proxy configurations through
+[mod_proxy](http://httpd.apache.org/docs/2.4/mod/mod_proxy.html). Apache 2.4.5
+and later also support proxying of WebSocket through a sub-module called
+[mod_proxy_wstunnel](http://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html).
+Both of these modules will need to be enabled for proxying of Guacamole to work
+properly.
+
+Lacking mod_proxy_wstunnel, it is still possible to proxy Guacamole, but
+Guacamole will be unable to use WebSocket. It will instead fallback to using
+the HTTP tunnel, resulting in reduced performance.
+
+(proxying-with-apache)=
+
+### Proxying Guacamole
+
+Configuring Apache to proxy HTTP requests requires using the `ProxyPass` and
+`ProxyPassReverse` directives, which are provided by the mod_proxy module.
+These directives describe how HTTP traffic should be routed to the web server
+behind the proxy:
+
+```apache
+<Location /guacamole/>
+ Order allow,deny
+ Allow from all
+ ProxyPass http://HOSTNAME:8080/guacamole/ flushpackets=on
+ ProxyPassReverse http://HOSTNAME:8080/guacamole/
+</Location>
+```
+
+Here, `HOSTNAME` is the hostname or IP address of the machine hosting your
+servlet container, and `8080` is the port that servlet container is configured
+to use. You will need to replace these values with the correct values for your
+server.
+
+:::{important}
+*Do not forget the `flushpackets=on` option.*
+
+Most proxies, including mod_proxy, will buffer all data sent over the
+connection, waiting until the connection is closed before sending that data to
+the client. As Guacamole's HTTP tunnel relies on streaming data to the client
+over an open connection, excessive buffering will effectively block Guacamole
+connections, rendering Guacamole useless.
+
+*If the option `flushpackets=on` is not specified, Guacamole may not work*.
+:::
+
+(websocket-and-apache)=
+
+### Proxying the WebSocket tunnel
+
+Apache will not automatically proxy WebSocket connections, but you can proxy
+them separately with Apache 2.4.5 and later using mod_proxy_wstunnel. After
+enabling mod_proxy_wstunnel a secondary `Location` section can be added which
+explicitly proxies the Guacamole WebSocket tunnel, located at
+`/guacamole/websocket-tunnel`:
+
+:::{code-block} apache
+:emphasize-lines: 8-13
+<Location /guacamole/>
+ Order allow,deny
+ Allow from all
+ ProxyPass http://HOSTNAME:8080/guacamole/ flushpackets=on
+ ProxyPassReverse http://HOSTNAME:8080/guacamole/
+</Location>
+
+<Location /guacamole/websocket-tunnel>
+ Order allow,deny
+ Allow from all
+ ProxyPass ws://HOSTNAME:8080/guacamole/websocket-tunnel
+ ProxyPassReverse ws://HOSTNAME:8080/guacamole/websocket-tunnel
+</Location>
+:::
+
+Lacking this, Guacamole will still work by using normal HTTP, but network
+latency will be more pronounced with respect to user input, and performance may
+be lower.
+
+:::{important}
+**The `Location` section for `/guacamole/websocket-tunnel` must be placed after
+the `Location` section for the rest of Guacamole.**
+
+Apache evaluates all Location sections, giving priority to the last section
+that matches. If the `/guacamole/websocket-tunnel` section comes first, the
+section for `/guacamole/` will match instead, and WebSocket will not be proxied
+correctly.
+:::
+
+(changing-path-with-apache)=
+
+### Changing the path
+
+If you wish to serve Guacamole through Apache under a path other than
+`/guacamole/`, the easiest method is to simply rename the `.war` file. For
+example, if intending to server Guacamole at `/new-path/`, you would:
+
+1. Rename `guacamole.war` to `new-path.war`.
+
+2. Update the paths within the Apache configuration to reflect the new path:
+
+ :::{code-block} apache
+ :emphasize-lines: 1,4-5,8,11-12
+ <Location /new-path/>
+ Order allow,deny
+ Allow from all
+ ProxyPass http://HOSTNAME:8080/new-path/ flushpackets=on
+ ProxyPassReverse http://HOSTNAME:8080/new-path/
+ </Location>
+
+ <Location /new-path/websocket-tunnel>
+ Order allow,deny
+ Allow from all
+ ProxyPass ws://HOSTNAME:8080/new-path/websocket-tunnel
+ ProxyPassReverse ws://HOSTNAME:8080/new-path/websocket-tunnel
+ </Location>
+ :::
+
+Alternatively, the configuration can be altered slightly to handle requests at
+a different location externally while still serving internal requests at
+`/guacamole/`:
+
+:::{code-block} apache
+:emphasize-lines: 1,8
+<Location /new-path/>
+ Order allow,deny
+ Allow from all
+ ProxyPass http://HOSTNAME:8080/guacamole/ flushpackets=on
+ ProxyPassReverse http://HOSTNAME:8080/guacamole/
+</Location>
+
+<Location /new-path/websocket-tunnel>
+ Order allow,deny
+ Allow from all
+ ProxyPass ws://HOSTNAME:8080/guacamole/websocket-tunnel
+ ProxyPassReverse ws://HOSTNAME:8080/guacamole/websocket-tunnel
+</Location>
+:::
+
+(disable-tunnel-logging)=
+
+### Disabling logging of tunnel requests
+
+If WebSocket is unavailable, Guacamole will fallback to using an HTTP-based
+tunnel. The Guacamole HTTP tunnel works by transferring a continuous stream of
+data over multiple short-lived streams, each associated with a separate HTTP
+request. By default, Apache will log each of these requests, resulting in a
+rather bloated access log.
+
+There is little value in a log file filled with identical tunnel requests, so
+it is recommended to explicitly disable logging of those requests. Apache does
+provide a means of matching URL patterns and setting environment variables
+based on whether the URL matches. Logging can then be restricted to requests
+which lack this environment variable:
+
+```apache
+SetEnvIf Request_URI "^/guacamole/tunnel" dontlog
+CustomLog /var/log/apache2/guac.log common env=!dontlog
+```
+
+Note that if you are serving Guacamole under a path different from
+`/guacamole/`, you will need to change the value of `Request_URI` above
+accordingly.
+
diff --git a/src/saml-auth.md b/src/saml-auth.md
new file mode 100644
index 0000000..4c863f6
--- /dev/null
+++ b/src/saml-auth.md
@@ -0,0 +1,122 @@
+SAML Authentication
+===================
+
+SAML is a widely implemented and used Single Sign On (SSO) provider that allows
+applications and services to authenticate in a standard way, and brokers those
+authentication requests to one or more back-end authentication providers. The
+SAML authentication extension allows Guacamole to redirect to a SAML Identity
+Provider (IdP) for authentication and user services. This module does not
+provide any capability for storing or retrieving connections, and must be
+layered with other authentication extensions that provide connection
+management.
+
+(saml-downloading)=
+
+Downloading the SAML authentication extension
+---------------------------------------------
+
+The SAML authentication extension is available separately from the main
+`guacamole.war`. The link for this and all other officially-supported and
+compatible extensions for a particular version of Guacamole are provided on the
+release notes for that version. You can find the release notes for current
+versions of Guacamole here: <http://guacamole.apache.org/releases/>.
+
+The SAML authentication extension is packaged as a `.tar.gz` file containing
+only the extension itself, `guacamole-auth-saml-1.3.0.jar`, which must
+ultimately be placed in `GUACAMOLE_HOME/extensions`.
+
+(installing-saml-auth)=
+
+Installing SAML authentication
+------------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located within
+the `GUACAMOLE_HOME/extensions` directory. *If you are unsure where
+`GUACAMOLE_HOME` is located on your system, please consult
+[](configuring-guacamole) before proceeding.*
+
+To install the SAML authentication extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+ exist.
+
+2. Copy `guacamole-auth-saml-1.3.0.jar` within `GUACAMOLE_HOME/extensions`.
+
+3. Configure Guacamole to use SAML authentication, as described below.
+
+(guac-saml-config)=
+
+### Configuring Guacamole for SAML Authentication
+
+The SAML authentication extension provides several configuration properties to
+set it up to talk to the IdP. The SAML IdP also must be configured with
+Guacamole as a Service Provider (SP). Configuration of the SAML IdP is beyond
+the scope of this document, and will vary widely based on the IdP in use.
+
+`saml-idp-metadata-url`
+: The URI of the XML metadata file that from the SAML Identity Provider that
+ contains all of the information the SAML extension needs in order to know how
+ to authenticate with the IdP. This URI can either be a remote server (e.g.
+ `https://`) or a local file on the filesystem (e.g. `file://`). Often the
+ metadata file contains most of the required properties for SAML
+ authentication and the other parameters are not required.
+
+`saml-idp-url`
+: The base URL of the SAML IdP. This is the URL that the SAML authentication
+ extension will use to redirect when requesting SAML authentication. If the
+ `saml-idp-metadata-url` property is provided, this parameter will be ignored.
+ If the metadata file is not provided this property is required.
+
+`saml-entity-id`
+: The entity ID of the Guacamole SAML client, which is generally the URL of the
+ Guacamole server, but is not required to be so. This property is required if
+ either the `saml-idp-metadata-url` property is not specified, or if the
+ provided metadata file does not contain the SAML SP Entity ID for Guacamole
+ Client.
+
+`saml-callback-url`
+: The URL that the IdP will use once authentication has succeeded to return to
+ the Guacamole web application and provide the authentication details to the
+ SAML extension. The SAML extension currently only supports callback as a POST
+ operation to this callback URL. This property is required.
+
+`saml-strict`
+: Require strict security checks during SAML logins. This will insure that
+ valid certificates are present for all interactions with SAML servers and
+ fail SAML authentication if security restrictions are violated. This property
+ is optional, and will default to true, requiring strict security checks. This
+ property should only be set to false in non-production environments during
+ testing of SAML authentication.
+
+`saml-debug`
+: Enable additional logging within the supporting SAML library that can assist
+ in tracking down issues during SAML logins. This property is optional, and
+ will default to false (no debugging).
+
+`saml-compress-request`
+: Enable compression of the HTTP requests sent to the SAML IdP. This property
+ is optional and will default to true (compression enabled).
+
+`saml-compress-response`
+: Request that the SAML response returned by the IdP be compressed. This
+ property is optional and will default to true (compression will be
+ requested).
+
+`saml-group-attribute`
+: The name of the attribute provided by the SAML IdP that contains group
+ membership of the user. These groups will be parsed and used to map group
+ membership of the user logging in, which can be used for permissions
+ management within Guacamole Client, particularly when layered with other
+ authentication modules. This property is optional, and defaults to "groups".
+
+(completing-saml-install)=
+
+### Completing the installation
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before SAML authentication can be used. *Doing this will disconnect all active
+users, so be sure that it is safe to do so prior to attempting installation.*
+When ready, restart your servlet container and give the new authentication a
+try.
+
diff --git a/src/site.xslt b/src/site.xslt
deleted file mode 100644
index 8ac485c..0000000
--- a/src/site.xslt
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- Stylesheet for translating DocBook into XHTML -->
-<xsl:stylesheet
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- version="1.0">
-
- <xsl:import href="../docbook-xsl/xhtml/chunk.xsl"/>
-
- <!-- Name chunk files after root element IDs -->
- <xsl:param name="use.id.as.filename">1</xsl:param>
-
- <!-- Limit TOC to only top-level children -->
- <xsl:param name="toc.max.depth">2</xsl:param>
-
- <xsl:param name="generate.toc">
- appendix toc,title
- article/appendix nop
- article toc,title
- book toc,title
- chapter toc,title
- part toc,title
- preface title
- qandadiv toc
- qandaset toc
- reference toc,title
- sect1 toc
- sect2 toc
- sect3 toc
- sect4 toc
- sect5 toc
- section toc
- set toc,title
- </xsl:param>
-
- <!-- Custom stylesheet -->
- <xsl:param name="html.stylesheet" select="'gug.css'"/>
-
- <!-- No inline styles for admonitions -->
- <xsl:param name="admon.style"></xsl:param>
-
- <!-- Chunk only at chapter level -->
- <xsl:param name="chunk.section.depth" select="0"/>
-
- <!-- Do not surround images with tables -->
- <xsl:param name="make.graphic.viewport" select="0"/>
-
- <!-- Custom header -->
- <xsl:template name="user.header.navigation">
- <xsl:text disable-output-escaping="yes"><![CDATA[
- <!-- CONTENT -->
-
- <div id="page"><div id="content">
- ]]></xsl:text>
- </xsl:template>
-
- <!-- Custom footer -->
- <xsl:template name="user.footer.navigation">
- <xsl:text disable-output-escaping="yes"><![CDATA[
-
- </div></div>
- ]]></xsl:text>
- </xsl:template>
-
- <!-- Modify header to include mobile-friendly viewport meta tag -->
- <xsl:template name="user.head.content">
- <xsl:text disable-output-escaping="yes"><![CDATA[
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi"/>
- ]]></xsl:text>
- </xsl:template>
-
-</xsl:stylesheet>
diff --git a/src/totp-auth.md b/src/totp-auth.md
new file mode 100644
index 0000000..78a7dc7
--- /dev/null
+++ b/src/totp-auth.md
@@ -0,0 +1,168 @@
+TOTP two-factor authentication
+==============================
+
+Guacamole supports TOTP as a second authentication factor, layered on top of
+any other authentication extension, including those available from the main
+project website, providing [base requirements for key storage and
+enrollment](totp-prerequisites) are met. The TOTP authentication extension
+allows users to be additionally verified against a user-specific and secret key
+generated during [enrollment of their authentication device](totp-enrollment).
+
+:::{important}
+This chapter involves modifying the contents of `GUACAMOLE_HOME` - the
+Guacamole configuration directory. If you are unsure where `GUACAMOLE_HOME` is
+located on your system, please consult [](configuring-guacamole) before
+proceeding.
+:::
+
+(totp-prerequisites)=
+
+Prerequisites
+-------------
+
+The enrollment process used by Guacamole's TOTP support needs to be able
+to store an automatically-generated key within the user's account.
+Another extension must be installed which supports storage of arbitrary
+data from other extensions. *Currently the only extensions provided with
+Guacamole which support this kind of storage are the [database
+authentication extensions](jdbc-auth).*
+
+It is thus recommended that authentication against a database be fully
+configured prior to setting up TOTP. Instructions walking through the setup of
+database authentication for Guacamole are provided in [](jdbc-auth).
+
+(totp-architecture)=
+
+How TOTP works with Guacamole
+-----------------------------
+
+Guacamole provides support for TOTP as a second authentication factor. To make
+use of the TOTP authentication extension, some other authentication mechanism
+will need be configured, as well. When a user attempts to log into Guacamole,
+other installed authentication methods will be queried first:
+
+
+
+Only after authentication has succeeded with one of those methods will
+Guacamole prompt the user to further verify their identity with an
+authentication code:
+
+
+
+If both the initial authentication attempt and verification using TOTP succeed,
+the user will be allowed in. If either mechanism fails, access to Guacamole is
+denied.
+
+(totp-enrollment)=
+
+### Enrollment
+
+If the user does not yet have a TOTP key associated with their account (they
+have not yet completed enrollment), they will be required to enroll an
+authentication device after passing the first authentication factor. A QR code
+containing an automatically-generated key will be presented to the user to be
+scanned by their authentication app or device:
+
+
+
+If the authentication device does not support scanning QR codes for enrollment,
+the details within the QR code can be revealed by clicking the "Show" link next
+to the "Details" header. These values can then be entered manually:
+
+
+
+Enrollment is completed once the user enters a valid authentication code
+generated by their device using the provided key.
+
+(totp-downloading)=
+
+Downloading the TOTP extension
+------------------------------
+
+The TOTP authentication extension is available separately from the main
+`guacamole.war`. The link for this and all other officially-supported and
+compatible extensions for a particular version of Guacamole are provided on the
+release notes for that version. You can find the release notes for current
+versions of Guacamole here: <http://guacamole.apache.org/releases/>.
+
+The TOTP authentication extension is packaged as a `.tar.gz` file containing
+only the extension itself, `guacamole-auth-totp-1.3.0.jar`, which must
+ultimately be placed in `GUACAMOLE_HOME/extensions`.
+
+(installing-totp-auth)=
+
+Installing TOTP authentication
+------------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located within
+the `GUACAMOLE_HOME/extensions` directory. To install the TOTP authentication
+extension, you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+ exist.
+
+2. Copy `guacamole-auth-totp-1.3.0.jar` within `GUACAMOLE_HOME/extensions`.
+
+3. Configure Guacamole to use TOTP authentication, as described below.
+
+:::{important}
+You will need to restart Guacamole by restarting your servlet container in
+order to complete the installation. Doing this will disconnect all active
+users, so be sure that it is safe to do so prior to attempting installation. If
+you do not configure the TOTP authentication properly, Guacamole will not start
+up again until the configuration is fixed.
+:::
+
+(guac-totp-config)=
+
+### Configuring Guacamole for TOTP
+
+With the exception of [the storage and permission requirements described
+above](totp-prerequisites), the TOTP extension should work out-of-the-box
+without any additional configuration. Defaults have been chosen for all
+configuration parameters such that the TOTP extension will be compatible with
+Google Authenticator and similar, popular TOTP implementations.
+
+If your intended authentication application or device has different
+requirements, or you wish to override the defaults, additional properties may
+be specified within `guacamole.properties`:
+
+`totp-issuer`
+: The human-readable name of the entity issuing user accounts. If not
+ specified, "Apache Guacamole" will be used by default.
+
+`totp-digits`
+: The number of digits which should be included in each generated TOTP code.
+ Legal values are 6, 7, or 8. By default, 6-digit codes are generated.
+
+`totp-period`
+: The duration that each generated code should remain valid, in seconds. By
+ default, each code remains valid for 30 seconds.
+
+`totp-mode`
+: The hash algorithm that should be used to generate TOTP codes. Legal values
+ are "sha1", "sha256", and "sha512". By default, "sha1" is used.
+
+(completing-totp-install)=
+
+### Completing the installation
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before TOTP authentication will take effect. Restart your servlet container
+and give the new authentication a try.
+
+:::{important}
+You only need to restart your servlet container. *You do not need to restart
+guacd*.
+
+guacd is completely independent of the web application and does not deal with
+`guacamole.properties` or the authentication system in any way. Since you are
+already restarting the servlet container, restarting guacd as well technically
+won't hurt anything, but doing so is completely pointless.
+:::
+
+If Guacamole does not come back online after restarting your servlet container,
+check the logs. Problems in the configuration of the TOTP extension may prevent
+Guacamole from starting up, and any such errors will be recorded in the logs of
+your servlet container.
diff --git a/src/troubleshooting.md b/src/troubleshooting.md
new file mode 100644
index 0000000..dc62767
--- /dev/null
+++ b/src/troubleshooting.md
@@ -0,0 +1,542 @@
+Troubleshooting
+===============
+
+(not-working)=
+
+It isn't working
+----------------
+
+If Guacamole isn't working, chances are something isn't configured properly, or
+something is wrong with the network. Thankfully, Guacamole and all its
+components log errors thoroughly, so the problem can usually be traced down
+fairly easily if you know where to look. Troubleshooting Guacamole usually
+boils down to checking either syslog or your servlet container's logs (likely
+Tomcat).
+
+Failing all that, you can always post a question on [one of the project mailing
+lists](http://guacamole.apache.org/support/#mailing-lists), or if you truly
+feel you've discovered a bug, you can [create a new ticket in
+JIRA](https://issues.apache.org/jira/browse/GUACAMOLE/). Beware that if
+something isn't working, and there are errors in the logs describing the
+problem, [it is usually not a
+bug](http://guacamole.apache.org/faq/#probably-not-a-bug), and the best place
+to handle such things is through consulting this guide or the mailing lists.
+
+### No graphics appear
+
+If you *never* see any graphics appear, or you see "Connecting, waiting for
+first update..." for a while and then are disconnected, the most likely cause
+is a proxy.
+
+Guacamole relies on streaming data to you over a persistent connection. If
+software between Guacamole and your browser is buffering all incoming data,
+such as a proxy, this data never makes it to your browser, and you will just
+see it wait indefinitely. Eventually, thinking the client has disconnected,
+Guacamole closes the connection, at which point the proxy finally flushes its
+buffer and you see graphics! ... just in time to see it disconnect.
+
+The solution here is to either modify your proxy settings to flush packets
+immediately as they are received, or to use HTTPS. Proxies are required to pass
+HTTPS through untouched, and this usually solves the problem.
+
+Even if you aren't aware of any proxy, there may be one in place. Corporate
+firewalls very often incorporate proxies. Antivirus software may buffer
+incoming data until the connection is closed and the data is scanned for
+viruses. Virtualization software may detect HTTP data and buffer the connection
+just like a proxy. If all else fails, try HTTPS - it's the only secure way to
+do this anyway.
+
+### Connections involving Unicode don't work
+
+If you are using Tomcat, beware that you *must* set the `URIEncoding="UTF-8"`
+attribute on all connectors in your `server.xml`. If you are using a different
+servlet container, you need to find out whether it requires special options to
+support UTF-8 in URIs, and change the required settings to enable such support.
+
+Without UTF-8 support enabled for URIs, Unicode characters in connection names
+will not be received properly when connecting, and Guacamole will think the
+connection you requested does not exist. Similarly, if you are using the
+built-in administration interface, parameters involving Unicode characters will
+not save properly without these options enabled.
+
+syslog
+------
+
+guacd and libguac-based programs (such as all client plugins) log informational
+messages and errors to syslog. Specifically, guacd uses syslog, and it exposes
+this logging facility to everything it loads (client plugins), thus if the VNC
+or RDP support plugins encounter errors, they log those errors over the logging
+facilities exposed by guacd, in this case syslog.
+
+Once you guacd is started, you'll see entries like the following in syslog:
+
+```
+guacd[19663]: Guacamole proxy daemon (guacd) version 0.7.0
+guacd[19663]: Unable to bind socket to host ::1, port 4823: Address family
+ not supported by protocol
+guacd[19663]: Successfully bound socket to host 127.0.0.1, port 4823
+guacd[19663]: Exiting and passing control to PID 19665
+guacd[19665]: Exiting and passing control to PID 19666
+guacd[19666]: Listening on host 127.0.0.1, port 4823
+```
+
+Each entry relevant to Guacamole has the prefix "guacd", denoting the program
+that produced the entry, followed by the process ID, followed by the message.
+The entries above show guacamole starting successfully and listening on a
+non-default port 4823.
+
+### guacd errors
+
+#### Unable to bind socket to any addresses.
+
+This means that guacd failed to start up at all because the port it wants to
+listen on is already taken at all addresses attempted. The details of what
+guacd tried will be listed in the log entries above this. To solve the problem,
+find what port guacd was trying to listen on (the default is 4822) and check if
+any other service is listening on that port.
+
+If another service is listening on the default port, you can always specify a
+non-standard port for guacd by using the `-l PORT` option (that's a lowercase
+"L", not a number "1"), where <PORT> is the number of the port to listen on.
+Beware that you will likely have to modify `guacamole.properties` so that
+Guacamole knows how to connect to guacd.
+
+#### Unable to start input thread
+
+guacd creates two threads for each connection: one that receives input from the
+connected client, and the other that produces output for the client. If either
+of these fails to start, the above error will be logged along with the cause.
+
+If it is the output thread that fails to start, the message will instead read:
+"Unable to start output thread".
+
+#### Client finished abnormally
+
+If the client plugin ever returns an error code, this will cause the connection
+to immediately terminate, with the cause of the error specific to the plugin in
+use. The cause should be detailed in the log messages above the error. If those
+log messages don't make sense, you may have found a bug.
+
+#### Could not fork() parent
+
+When guacd starts up, it immediately attempts to "fork" into the background
+(unless instructed otherwise). The word "fork()" above is a reference to the C
+function call that does this. There are several calls to this function, each of
+which might fail if system resources are lacking or something went wrong at a
+low level. If you see this message, it is probably not a bug in Guacamole, but
+rather a problem with the load level of your system.
+
+This message may also appear as "Could not fork() group leader".
+
+#### Unable to change working directory to /
+
+One of the duties of guacd as it starts up is to change its working directory
+to the root directory. This is to prevent locking the current directory in case
+it needs to be unmounted, etc. If guacd cannot do this, this error will be
+logged, along with the cause.
+
+#### Unable to redirect standard file descriptors to /dev/null
+
+As guacd starts, it also has to redirect STDOUT, STDERR, and STDIN to
+`/dev/null` such that attempts to use these output mechanisms do not pollute
+the active console. Though guacd and client plugins will use the exposed
+logging facilities (and thus syslog) rather than STDOUT or STDERR, libraries
+used by client plugins are often written only from the mindset of a typical
+client, and use standard output mechanisms for debug logging. Not redirecting
+these would result in undesired output to the console.
+
+If guacd cannot redirect these file descriptors for any reason, this error will
+be logged, along with the cause.
+
+#### Error parsing given address or port: HOSTNAME
+
+If you specified a host or port to listen on via commandline options, and that
+host or port is actually invalid, you will see this error. Fix the
+corresponding option and try again.
+
+#### Error opening socket
+
+When guacd starts up, it needs to open a socket and then listen on that socket.
+If it can't even open the socket, this error will be logged, and guacd will
+exit. The cause is most likely related to permissions, and is logged along with
+the error.
+
+#### Unable to resolve host
+
+If the hostname you specified on the commandline cannot be found, you will see
+this error. Note that this error is from guacd, and does not relate to whatever
+remote desktop servers you may be trying to use; it relates only to the host
+guacd is trying to listen on. Check the hostname or IP address specified on the
+commandline. If that checks out, there may be a problem with your DNS or your
+network.
+
+#### Could not become a daemon
+
+In order to become a "daemon" (that is, in order to run in the background as a
+system process), guacd must create and exit from several processes, redirect
+file descriptors, etc. If any of these steps fails, guacd will not become a
+daemon, and it will log this message and exit. The reason guacd could not
+become a daemon will be in the previous error message in the logs.
+
+#### Could not write PID file
+
+guacd offers a commandline option that lets you specify a file that it should
+write its process ID into, which is useful for init scripts. If you see this
+error, it likely means the user guacd is running as does not have permission to
+write this file. The true cause of the error will be logged in the same entry.
+Check which user guacd is running as, and then check that it has write
+permission to the file in question.
+
+#### Could not listen on socket
+
+When guacd starts up, it needs to listen on the socket it just opened in order
+to accept connections. If it cannot listen on the socket, clients will be
+unable to connect. If, for any reason, guacd is unable to listen on the socket,
+guacd will exit and log this message along with the cause, which is most likely
+a low-level system resource problem.
+
+#### Could not accept client connection
+
+When a client connects to guacd, it must accept the connection in order for
+communication to ensue. If it cannot even accept the connection, no
+communication between server and client will happen, and this error will be
+logged. The cause of the error will be logged in the same entry. Possible
+causes include permissions problems, or lack of server resources.
+
+#### Error forking child process
+
+When a client connects to guacd, it must create a new process to handle the
+connection while the old guacd process continues to listen for new connections.
+If, for any reason, guacd cannot create this process, the connection from that
+client will be denied, and the cause of the error will be logged. Possible
+causes include permissions problems, or lack of server resources.
+
+#### Error closing daemon reference to child descriptor
+
+When guacd receives a connection, and it creates a new process to handle that
+connection, it gains a copy of the file descriptor that the client will use for
+communication. As this connection can never be closed unless all references to
+the descriptor are closed, the server must close its copy such that the client
+is the only remaining holder of the file descriptor. If the server cannot close
+the descriptor, it will log this error message along with the cause.
+
+#### Error sending "sync" instruction
+
+During the course of a Guacamole session, guacd must occasionally "ping" the
+client to make sure it is still alive. This ping takes the form of a "sync"
+instruction, which the client is obligated to respond to as soon as it is
+received. If guacd cannot send this instruction, this error will be logged,
+along with the cause. Chances are the connection has simply been closed, and
+this error can be ignored.
+
+#### Error flushing output
+
+After the client plugin is finished (for the time being) with handling server
+messages, the socket is automatically flushed. If the server cannot flush this
+socket for some reason, such as the connection already being closed, you will
+see this error. Normally, this error does not indicate a problem, but rather
+that the client has simply closed the connection.
+
+#### Error handling server messages
+
+While the client plugin is running, guacd will occasionally ask the plugin to
+check and handle any messages that it may have received from the server it
+connected to. If the client plugin fails for some reason while doing this, this
+error will be logged, and the cause of the error will likely be logged in
+previous log entries by the client plugin.
+
+#### Error reading instruction
+
+During the course of a Guacamole session, instructions are sent from client to
+server which are to be handled by the client plugin. If an instruction cannot
+be read, this error will be logged. Usually this means simply that the
+connection was closed, but it could also indicate that the version of the
+client in use is so old that it doesn't support the current Guacamole protocol
+at all. If the cause looks like the connection was closed (end of stream
+reached, etc.), this log entry can be ignored. Otherwise, if the first two
+numbers of the version numbers of all Guacamole components match, you have
+probably found a bug.
+
+#### Client instruction handler error
+
+This error indicates that a client plugin failed inside the handler for a
+specific instruction. When the server receives instructions from the client, it
+then invokes specific instruction handlers within the client plugin. In
+general, this error is not useful to a user or system administrator. If the
+cause looks benign, such as reaching the end of a stream (the connection
+closed), it can be ignored as normal. Otherwise, this error can indicate a bug
+either in the client plugin or in a library used by the client plugin.
+
+It can also indicate a problem in the remote desktop server which is causing
+the client plugin to fail while communicating with it.
+
+#### Error reading OPCODE
+
+During the handshake of the Guacamole protocol, the server expects a very
+specific sequence of instructions to be received. If the wrong instructions are
+received, or the connection is abruptly closed during the handshake, the above
+error will occur.
+
+In the case that the cause is the connection closing, this is normal, and
+probably just means that the client disconnected before the initial handshake
+completed.
+
+If the connection was not closed abruptly, but instead the wrong instruction
+was received, this could mean either that the connecting client is from an
+incompatible version of Guacamole (and thus does not know the proper handshake
+procedure) or you have found a bug. Check whether all installed components came
+from the same upstream release bundle.
+
+#### Error sending "args"
+
+During the handshake of the Guacamole protocol, the server must expose all
+parameters used by the client plugin via the args instruction. If this cannot
+be sent, you will see this error in the logs. The cause will be included in the
+error message, and usually just indicates that the connection was closed during
+the handshake, and thus the handshake cannot continue.
+
+#### Error loading client plugin
+
+When the client connects, it sends an instruction to guacd informing it what
+protocol it wishes to use. If the corresponding client plugin cannot be found
+or used for any reason, this message will appear in the logs. Normally this
+indicates that the corresponding client plugin is not actually installed. The
+cause listed after the error message will indicate whether this is the case.
+
+#### Error instantiating client
+
+After the client plugin is loaded, an initialization function provided by the
+client plugin is invoked. If this function fails, then the client itself cannot
+be created, and this error will be logged. Usually this indicates that one or
+more of the parameters given to the client plugin are incorrect or malformed.
+Check the configuration of the connection in use at the time.
+
+### libguac-client-vnc errors
+
+#### Error waiting for VNC message
+
+The VNC client plugin must wait for messages sent by the VNC server, and handle
+them when they arrive. If there was an error while waiting for a message from
+the VNC server, this error message will be displayed. Usually this means that
+the VNC server closed the connection, or there is a problem with the VNC server
+itself, but the true cause of the error will be logged.
+
+#### Error handling VNC server message
+
+When messages are received from the VNC server, libvncclient must handle them
+and then invoke the functions of libguac-client-vnc as necessary. If
+libvncclient fails during the handling of a received message, this error will
+be logged, along with (hopefully) the cause. This may indicate a problem with
+the VNC server, or a lack of support within libvncclient.
+
+#### Wrong argument count received
+
+The connecting client is required to send exactly the same number of arguments
+as requested by the client plugin. If you see this message, it means there is a
+bug in the client connecting to guacd, most likely the web application.
+
+### libguac-client-rdp errors
+
+#### Invalid PARAMETER
+
+If one of the parameters given, such as "width", "height", or "color-depth", is
+invalid (not an integer, for example), you will receive this error. Check the
+parameters of the connection in use and try again.
+
+#### Support for the CLIPRDR channel (clipboard redirection) could not be loaded
+
+FreeRDP provides a plugin which provides clipboard support for RDP. This plugin
+is typically built into FreeRDP, but some distributions may bundle this
+separately. libguac-client-rdp loads this plugin in order to support clipboard,
+as well. If this plugin could not be loaded, then clipboard support will not be
+available, and the reason will be logged.
+
+#### Cannot create static channel "NAME": failed to load "guac-common-svc" plugin for FreeRDP
+
+RDP provides support for much of its feature set through static virtual
+channels. Sound support, for example is provided through the "RDPSND" channel.
+Device redirection for printers and drives is provided through "RDPDR". To
+support these and other static virtual channels, libguac-client-rdp builds a
+plugin for FreeRDP called "guac-common-svc" which allows Guacamole to hook into
+the parts of FreeRDP that support virtual channels.
+
+If libguac-client-rdp cannot load this plugin, support for any features which
+leverage static virtual channels will not work, and the reason will be logged.
+A likely explanation is that libguac-client-rdp was built from source, and the
+directory specified for FreeRDP's installation location was incorrect. For
+FreeRDP to be able to find plugins, those plugins must be placed in the
+`freerdp2/` subdirectory of whichever directory contains the `libfreerdp2.so`
+library.
+
+#### Server requested unsupported clipboard data type
+
+When clipboard support is loaded, libguac-client-rdp informs the RDP server of
+all supported clipboard data types. The RDP server is required to send only
+those types supported by the client. If the server decides to send an
+unsupported type anyway, libguac-client-rdp ignores the data sent, and logs
+this message.
+
+#### Clipboard data missing null terminator
+
+When text is sent via a clipboard message, it is required to have a terminating
+null byte. If this is not the case, the clipboard data is invalid, and
+libguac-client-rdp ignores it, logging this error message.
+
+Servlet container logs
+----------------------
+
+Your servlet container will have logs which the web application side of
+Guacamole will log errors to. In the case of Tomcat, this is usually
+`catalina.out` or `HOSTNAME.log` (for example, `localhost.log`).
+
+(user-mapping-xml-errors)=
+
+### `user-mapping.xml` errors
+
+Errors in the relating to the `user-mapping.xml` file usually indicate that
+either the XML is malformed, or the file itself cannot be found.
+
+#### Attribute "name" required for connection tag
+
+If you specify a connection with a `<connection>` tag, it must have a
+corresponding name set via the `name` attribute. If it does not, then the XML
+is malformed, and this error will be logged. No users will be able to login.
+
+#### Attribute "name" required for param tag
+
+Each parameter specified with a `<param>` tag must have a corresponding name
+set via the `name` attribute. If it does not, then the XML is malformed, and
+this error will be logged. No users will be able to login.
+
+#### Unexpected character data
+
+Character data (text not within angle brackets) can only exist within the
+`<param>` tag. If it exists elsewhere, then the XML is malformed, and this
+error will be logged. No users will be able to login.
+
+#### Invalid encoding type
+
+There are only two legal values for the `encoding` attribute of the
+`<authorize>` tag: `plain` (indicating plain text) and `md5` (indicating a
+value hashed with the MD5 digest). If any other value is used, then the XML is
+malformed, and this error will be logged. No users will be able to login.
+
+#### User mapping could not be read
+
+If for any reason the user mapping file cannot be read (the servlet container
+lacks read permission for the file, the file does not exist, etc.), this error
+will be logged. Check `guacamole.properties` to see where the user mapping file
+is specified to exist, and then check that is both exists and is readable by
+your servlet container.
+
+(guacamole-properties-errors)=
+
+### `guacamole.properties` errors
+
+If a property is malformed or a required property is missing, an error
+describing the problem will be logged.
+
+#### Property PROPERTY is required
+
+If Guacamole or an extension of Guacamole requires a specific property in
+`guacamole.properties`, but this property is not defined, this error will be
+logged. Check which properties are required by the authentication provider (or
+other extensions) in use, and then compare that against the properties within
+`guacamole.properties`.
+
+(guacamole-auth-errors)=
+
+### Authentication errors
+
+If someone attempts to login with invalid credentials, or someone attempts to
+access a resource or connection that does not exist or they do not have access
+to, errors regarding the invalid attempt will be logged.
+
+#### Cannot connect - user not logged in
+
+A user attempted to connect using the HTTP tunnel, and while the tunnel does
+exist and is attached to their session, they are not actually logged in.
+Normally, this isn't strictly possible, as a user has to have logged in for a
+tunnel to be attached to their session, but as it isn't an impossibility, this
+error does exist. If you see this error, it could mean that the user logged out
+at the same time that they made a connection attempt.
+
+#### Requested configuration is not authorized
+
+A user attempted to connect to a configuration with a given ID, and while that
+configuration does exist, they are not authorized to use it. This could mean
+that the user is trying to access things they have no privileges for, or that
+they are trying to access configurations they legitimately should, but are
+actually logged out.
+
+#### User has no session
+
+A user attempted to access a page that needs data from their session, but their
+session does not actually exist. This usually means the user has not logged in,
+as sessions are created through the login process.
+
+(guacamole-tunnel-errors)=
+
+### Tunnel errors
+
+The tunnel frequently returns errors if guacd is killed, the connection is
+closed, or the client abruptly closes the connection.
+
+#### No such tunnel
+
+An attempt was made to use a tunnel which does not actually exist. This is
+usually just the JavaScript client sending a leftover message or two while it
+hasn't realized that the server has disconnected. If this error happens
+consistently and is associated with Guacamole generally not working, it could
+be a bug.
+
+#### No tunnel created
+
+A connection attempt for a specific configuration was made, but the connection
+failed, and no tunnel was created. This is usually because the user was not
+authorized to use that connection, and thus no tunnel was created for access to
+that connection.
+
+#### No query string provided
+
+When the JavaScript client is communicating with the HTTP tunnel, it *must*
+provide data in the query string describing whether it wants to connect, read,
+or write. If this data is missing as the error indicates, there is a bug in the
+HTTP tunnel.
+
+#### Tunnel reached end of stream
+
+An attempt to read from the tunnel was made, but the tunnel in question has
+already reached the end of stream (the connection is closed). This is mostly an
+informative error, and can be ignored.
+
+#### Tunnel is closed
+
+An attempt to read from the tunnel was made, but the tunnel in question is
+already closed. This can happen if the client or guacd have closed the
+connection, but the client has not yet settled down and is still making read
+attempts. As there can be lags between when connections close and when the
+client realizes it, this can be safely ignored.
+
+#### End of stream during initial handshake
+
+If guacd closes the connection suddenly without allowing the client to complete
+the initial handshake required by the Guacamole protocol, this error will
+appear in the logs. If you see this error, you should check syslog for any
+errors logged by guacd to determine why it closed the connection so early.
+
+#### Element terminator of instruction was not ';' nor ','
+
+The Guacamole protocol imposes a strict format which requires individual parts
+of instructions (called "elements") to end with either a ";" or "," character.
+If they do not, then something has gone wrong during transmission. This usually
+indicates a bug in the client plugin in use, guacd, or libguac.
+
+#### Non-numeric character in element length
+
+The Guacamole protocol imposes a strict format which requires each element of
+an instruction to have a length prefix, which must be composed entirely of
+numeric characters (digits 0 through 9). If a non-numeric character is read,
+then something has gone wrong during transmission. This usually indicates a bug
+in the client plugin in use, guacd, or libguac.
+
diff --git a/src/using-guacamole.md b/src/using-guacamole.md
new file mode 100644
index 0000000..22fe250
--- /dev/null
+++ b/src/using-guacamole.md
@@ -0,0 +1,444 @@
+Using Guacamole
+===============
+
+Guacamole provides access to much of the functionality of a desktop from within
+your web browser. Although most people use remote desktop tools only when
+absolutely necessary, we believe that Guacamole must be aimed at becoming a
+primary means of accessing desktops, and the interface is thus intended to be
+as seamless and unobtrusive as possible.
+
+Home screen
+-----------
+
+Once you have successfully logged in, you will be taken to either the Guacamole
+home screen, where all available connections are listed, or directly to a
+connection, if you only have access to one connection.
+
+The home screen will contain a list of all connections to which you have
+access, along with thumbnails of any recently used or active connections. If
+you have access to a large number of connections and wish to quickly locate a
+specific connection, you can also enter search terms within the "Filter" field
+to filter the list of connections by name.
+
+
+
+Clicking on any connection will open that connection within the current window
+or tab, but multiple connections can be used simultaneously. You can easily
+navigate back to the home screen without disconnecting by using your browsers
+back button or the "Home" button in the Guacamole menu. Each connection you use
+will remain active until explicitly disconnected, or until you navigate away
+from Guacamole entirely. Active connections can be seen as thumbnails updating
+in real-time on the home screen.
+
+### User menu
+
+With the exception of the client screen discussed below, all Guacamole screens
+contain a menu in the upper-right corner called the "user menu". This menu
+displays your username and contains several options which depend on your user's
+level of access:
+
+Home
+: Navigates back to the home screen, if you are not already there. If you only
+ have access to one connection, this will be replaced with a link to that
+ connection.
+
+Settings
+: Navigates to the settings interface, which provides access to user
+ preferences such as display language. If you have access to administrative
+ functions, those are found within the settings interface, as well, and are
+ discussed in more detail in [](administration).
+
+Logout
+: Logs out of Guacamole completely, closing all current connections and ending
+ the Guacamole session.
+
+Client screen
+-------------
+
+Once you open a connection, you will see a real-time view of the remote
+display. You can interact with this display just as you would your normal
+desktop. Your mouse and keyboard will function as if they were connected
+directly to the remote machine.
+
+
+
+The remote display will take up the entire browser window, with no buttons or
+menus to disturb the view. With the intent of providing a seamless experience,
+options specific to remote desktop are hidden within the Guacamole menu, which
+can be opened as needed.
+
+(guacamole-menu)=
+
+### The Guacamole menu
+
+The Guacamole menu is a sidebar which is hidden until explicitly shown. On a
+desktop or other device which has a hardware keyboard, you can show this menu
+by pressing {kbd}`Ctrl+Alt+Shift`. If you are using a mobile or touchscreen
+device that lacks a keyboard, you can also show the menu by swiping right from
+the left edge of the screen. To hide the menu, you press {kbd}`Ctrl+Alt+Shift`
+again or swipe left across the screen.
+
+The Guacamole menu provides options for:
+
+* Navigating back to the home screen
+
+* Sharing the current connection
+
+* Reading from (and writing to) the clipboard of the remote desktop
+
+* Uploading and downloading files
+
+* Selecting alternative methods of typing or controlling the mouse,
+ particularly for use on mobile or touchscreen devices
+
+* Zooming in and out of the remote display
+
+* Disconnecting from the current connection entirely
+
+(using-the-clipboard)=
+
+Copying/pasting text
+--------------------
+
+At the top of the Guacamole menu is a text area labeled "clipboard"
+along with some basic instructions:
+
+> Text copied/cut within Guacamole will appear here. Changes to the text below
+> will affect the remote clipboard.
+
+The text area functions as an interface between the remote clipboard and the
+local clipboard. Text from the local clipboard can be pasted into the text
+area, causing that text to be sent to the clipboard of the remote desktop.
+Similarly, if you copy or cut text within the remote desktop, you will see that
+text within the text area, and can manually copy it into the local clipboard if
+desired.
+
+(client-user-menu)=
+
+Disconnecting and navigation
+----------------------------
+
+When you are done using the current connection, or you wish to navigate
+elsewhere temporarily, options to do so are within the user menu inside the
+Guacamole menu:
+
+
+
+The user menu within the Guacamole menu provides an additional "Disconnect"
+option that allows you to explicitly close the current connection only.
+Clicking "Logout" will also implicitly disconnect all active connections,
+including the current connection.
+
+Navigating back to the home screen or to the settings screen will not
+disconnect you: your connection will continue running in the background while
+you change settings or initiate another connection, and you can resume any
+active connection by clicking on it within the home screen.
+
+(client-share-menu)=
+
+Sharing the connection
+----------------------
+
+If the Guacamole server is configured to allow connection sharing, and you have
+been granted permission to share the current connection, an additional "Share"
+menu will appear next to your username in the Guacamole menu. Clicking on this
+menu opens a list of options for sharing the current connection.
+
+
+
+Clicking any of the options within the "Share" menu will immediately generate a
+unique share link which can be distributed to anyone, even to users which do
+not otherwise have accounts within the same Guacamole system.
+
+
+
+When the link is visited, that user will be given temporary access to your
+connection, restricted according to the sharing option chosen. This access, and
+the validity of the link overall, lasts only until you disconnect. Once the
+connection is closed, the link ceases to be valid, and any users sharing the
+connection with you will be disconnected.
+
+(file-transfer)=
+
+Transferring files
+------------------
+
+You can transfer files back and forth between your local computer and the
+remote desktop if it is supported by the underlying protocol and enabled on the
+connection. Currently, Guacamole supports file transfer for VNC, RDP, and SSH,
+using either the native file transfer support of the protocol or SFTP.
+
+Files can be transferred to the remote computer by dragging and dropping the
+files into your browser window, or through using the file browser located in
+the Guacamole menu.
+
+(file-browser)=
+
+### Using the file browser
+
+If file transfer is enabled on the connection, you will see one or more
+filesystem devices listed within the Guacamole menu. Clicking on one of the
+filesystems opens a file browser which lists the files and directories within
+that filesystem.
+
+
+
+Double-clicking on any directory will change the current location of the file
+browser to that directory, updating the list of files shown as well as the
+"breadcrumbs" at the top of the file browser. Clicking on any of the directory
+names listed in the breadcrumbs will bring you back to that directory, and
+clicking on the drive icon on the far left will bring you all the way back to
+the root level.
+
+Downloads are initiated by double-clicking on any file shown, while uploads are
+initiated by clicking the "Upload Files" button. Clicking "Upload Files" will
+open a file browsing dialog where you can choose one or more files from your
+local computer, ultimately uploading the selected files to the directory
+currently displayed within the file browser.
+
+The state of all file uploads can be observed within the notification dialog
+that appears once an upload begins, and can be cleared once completed by
+clicking the "Clear" button. Downloads are tracked through your browser's own
+download notification system.
+
+
+
+When you are done browsing the filesystem and transferring files, click "Back"
+to return to the Guacamole menu.
+
+(rdp-virtual-drive)=
+
+### The RDP virtual drive
+
+RDP provides its own native support for file transfer called "drive
+redirection" or "RDPDR". Guacamole provides support for this mechanism by
+emulating a virtual drive. Typically, this virtual drive will appear as a
+network drive within the RDP session. Files uploaded and downloaded will be
+preserved within this drive, even after disconnecting.
+
+
+
+Files can be downloaded from this drive using the file browser in the Guacamole
+menu or using the special "Download" folder within the virtual drive. All files
+dropped into this folder will automatically begin uploading to the client, and
+thus downloading through the browser.
+
+
+
+(guacctl)=
+
+### {program}`guacctl` / {program}`guacget`
+
+In addition to traditional drag-and-drop and the file browser, Guacamole's SSH
+support can be used with the {program}`guacctl` utility. The {program}`guacctl`
+utility is a simple shell script [included with Guacamole][guacctl] which
+allows you to use and configure file transfer directly from the command line
+within the SSH session:
+
+```console
+$ guacctl
+guacctl 0.8.0, Guacamole SSH session control utility.
+Usage: guacctl [OPTION] [FILE]...
+
+ -d, --download download each of the files listed.
+ -s, --set-directory set the destination directory for future uploaded
+ files.
+$ guacctl -d FILENAME
+$ guacctl -s DIRECTORY
+$
+```
+
+For convenience, you may also create a symbolic link or alias to
+{program}`guacctl` called {program}`guacget`. When run as {program}`guacget`,
+the utility behaves as if the `--download` option were supplied and initiates a
+download for each file specified on the command line.
+
+[guacctl]: https://raw.githubusercontent.com/apache/guacamole-server/master/bin/guacctl
+
+(using-the-osk)=
+
+On-screen keyboard
+------------------
+
+Certain key combinations are impossible to press within a web application like
+Guacamole because they are reserved by the operating system
+({kbd}`Ctrl+Alt+Del` or {kbd}`Alt+Tab`, for example) or by the web browser. If
+you press one of these reserved combinations, the effect will be observed
+locally, not remotely, and the remote desktop will receive only some of the
+keys.
+
+Guacamole provides its own, built-in on-screen keyboard which allows keys to be
+sent to the remote desktop without affecting the local system. If the device
+you're using does not have certain keys which the remote desktop depends on,
+such as the arrow keys or {kbd}`Ctrl`, you can use the on-screen keyboard for
+this, too. You can show the on-screen keyboard by selecting the "On-screen
+keyboard" option from the menu.
+
+Clicking (or tapping) the buttons of the on-screen keyboard has the same effect
+as pressing the same buttons on a real keyboard, except that the operating
+system and browser will not intercept these keypresses; they will only be sent
+to the remote desktop.
+
+(scaling-display)=
+
+Scaling the display
+-------------------
+
+Guacamole will default to shrinking or expanding the remote display to fit the
+browser window exactly, but this is not necessarily ideal. If the remote
+display is much larger than your local display, the screen may be impossible to
+see or interact with. This is especially true for mobile phones, whose screens
+need to be small enough to fit in the average hand.
+
+You can scale the display on touch devices by using the familiar pinch gesture.
+Place two fingers on the screen and bring them closer together to zoom out or
+further apart to zoom in.
+
+If your device lacks a touch screen, you can also control the zoom level
+through the menu. The controls for zooming in and out are located at the bottom
+of the menu. The current zoom level is displayed between two "-" and "+"
+buttons which control the zoom level in 10% increments.
+
+(touch-devices)=
+
+Mobile or touch devices
+-----------------------
+
+Guacamole is designed to work equally well across all HTML5 browsers, including
+those of mobile devices. It will automatically handle input from a touch screen
+or a traditional mouse (or both, if you happen to have such a gifted computer),
+and provides alternative input methods for devices which lack a physical
+keyboard.
+
+(touch-mouse)=
+
+### Mouse emulation
+
+In the case that your device has a touchscreen and lacks a mouse, Guacamole
+will emulate a mouse for the sake of interacting with remote desktops that
+expect mouse input. By default, Guacamole uses "absolute" mouse emulation. This
+means that the mouse pointer is positioned at the location of each tap on the
+screen.
+
+In both absolute and relative modes, you can click-and-drag by tapping the
+screen and then quickly placing your finger back down. This gesture only causes
+the mouse button to press down, but does not release it again until you lift
+your finger back up.
+
+(absolute-mouse-emulation)=
+
+#### Absolute mode (touchscreen)
+
+Absolute mouse emulation is the default as it tends to be what people expect
+when using a touch device to interact with applications designed for mouse
+input.
+
+Each tap on the screen is translated into a left-click at that position.
+Right-clicking is accomplished through pressing and holding your finger on the
+screen. If parts of the remote display are off-screen, you can drag your finger
+around the screen to pan the off-screen parts back into view.
+
+Although absolute mouse emulation works generally well, a finger makes for a
+very inaccurate pointing device. To address this, Guacamole also provides
+"relative" mouse emulation. Relative mouse emulation provides a way to deal
+with the need for accurate pointer control, when a true pointer device is not
+present.
+
+
+
+(relative-mouse-emulation)=
+
+#### Relative mode (touchpad)
+
+Guacamole's relative mouse emulation behaves similarly to the touchpad present
+on most modern laptops. You drag your finger across the display to move the
+mouse pointer, and tap the display to left-click. The pointer moves relative to
+the motion of your finger. Right-clicking is accomplished with a two-finger
+tap, and middle-clicking with a three-finger tap. The mouse scroll wheel can be
+operated by dragging two fingers up or down.
+
+Because the relative mouse emulation reserves so many gestures for the
+different mouse buttons and actions, common touch gestures like panning and
+pinch-to-zoom will not work while relative mouse emulation is enabled. Instead,
+the screen will automatically pan to keep the mouse pointer in view, and you
+can zoom through the buttons in the menu.
+
+
+
+(text-input)=
+
+### Typing without a physical keyboard
+
+Many mobile devices lack a physical keyboard entirely, and instead provide
+their own on-screen keyboards. As these are not true keyboards per se and do
+not produce key presses, Guacamole's text input mode is required for typing on
+these platforms.
+
+"Text input" allows input of keystrokes based on the input of text. Choosing
+"Text input" tells Guacamole to infer keystrokes by tracking text entered,
+rather than relying on actual key presses. Guacamole will instead determine the
+combination of keypresses necessary to produce the same pattern of input,
+including deletions.
+
+If you wish to type via an IME (input method editor), such as those required
+for Chinese, Japanese, or Korean, text input mode is required for this as well.
+Such IMEs function through the explicit insertion of text and do not send
+traditional key presses. Using text input mode within Guacamole thus allows you
+to use a locally-installed IME, without requiring the IME to be installed on
+the remote desktop.
+
+(preferences)=
+
+Changing preferences
+--------------------
+
+User preferences can be changed within the settings screen. These preferences
+are stored locally within the browser, so if you use multiple computers to
+access Guacamole, you can have different settings for each location. The
+settings screen allows users to change the language of the Guacamole interface,
+to change the default input method used by Guacamole connections, and to change
+the default mouse emulation mode for if a touch device is used. If you have
+sufficient permissions, you may also change your password, or administer the
+system.
+
+
+
+### Display language
+
+The Guacamole interface is currently available in English, Dutch, French,
+German, Italian, and Russian. By default, Guacamole will attempt to determine
+the appropriate display language by checking the language preferences of the
+browser in use. If this fails, or the browser is using a language not yet
+available within Guacamole, English will be used as a fallback.
+
+If you wish to override the current display language, you can do so by
+selecting a different language within the "Display language" field. The change
+will take effect immediately.
+
+(changing-password)=
+
+### Changing your password
+
+System administrators can restrict the ability of individual users to change
+their own passwords, so this section may not always be available. If your
+account *does* have permission, the preferences screen will contain a "Change
+Password" section.
+
+To change your password, you must provide your current password, enter the
+desired new password, and click "Update Password". You will remain logged in,
+and the change will affect any future login attempt.
+
+### Default input settings
+
+Guacamole provides multiple keyboard input methods and multiple mouse emulation
+modes. Many of these settings are specifically useful for touch devices, while
+others are aimed mainly at traditional desktop use. By default, Guacamole will
+use the keyboard and mouse modes most commonly preferred by users, but you can
+change these defaults if they do not fit your tastes or your current device.
+
+The choices available mirror those within the Guacamole menu discussed earlier
+in this chapter, and changing these settings will affect the default values
+selected within the Guacamole menu of future connections.
+
diff --git a/src/writing-you-own-guacamole-app.md b/src/writing-you-own-guacamole-app.md
new file mode 100644
index 0000000..306f29a
--- /dev/null
+++ b/src/writing-you-own-guacamole-app.md
@@ -0,0 +1,585 @@
+Writing your own Guacamole application
+======================================
+
+As Guacamole is an API, one of the best ways to put Guacamole to use is by
+building your own Guacamole-driven web application, integrating HTML5 remote
+desktop into whatever you think needs it.
+
+The Guacamole project provides an example of doing this called
+"guacamole-example", but this example is already completed for you, and from a
+quick glance at this example, it may not be obvious just how easy it is to
+integrate remote access into a web application. This tutorial will walk you
+through the basic steps of building an HTML5 remote desktop application using
+the Guacamole API and Maven.
+
+(basic-guacamole-architecture)=
+
+The basics
+----------
+
+Guacamole's architecture is made up of many components, but it's actually
+straightforward, especially from the perspective of the web application.
+
+Guacamole has a proxy daemon, guacd, which handles communication using remote
+desktop protocols, exposing those to whatever connects to it (in this case, the
+web application) using the Guacamole protocol. From where the web application
+is standing, it doesn't really matter that guacd dynamically loads protocol
+plugins or that it shares a common library allowing this; all that matters is
+that the web application just has to connect to port 4822 (where guacd listens
+by default) and use the Guacamole protocol. The architecture will take care of
+the rest.
+
+Thankfully, the Java side of the Guacamole API provides simple classes which
+already implement the Guacamole protocol with the intent of tunneling it
+between guacd and the JavaScript half of your web application. A typical web
+application leveraging these classes needs
+only the following:
+
+1. A class which extends `GuacamoleHTTPTunnelServlet`, providing the tunnel
+ between the JavaScript client (presumably using guacamole-common-js) and
+ guacd.
+
+ `GuacamoleHTTPTunnelServlet` is an abstract class which is provided by the
+ Guacamole API and already implements a fully functional, HTTP-based tunnel
+ which the tunneling objects already part of guacamole-common-js are written
+ to connect to. This class exists to make it easy for you to use Guacamole's
+ existing and robust HTTP tunnel implementation.
+
+ If you want to not use this class and instead use your own tunneling
+ mechanism, perhaps WebSocket, this is fine; the JavaScript object mentioned
+ above implements a common interface which you can also implement, and the
+ Guacamole JavaScript client which is also part of guacamole-common-js will
+ happily use your implementation as long as it provides that interface.
+
+2. A web page which includes JavaScript files from guacamole-common-js and uses
+ the client and tunnel objects to connect back to the web application.
+
+ The JavaScript API provided by the Guacamole project includes a full
+ implementation of the Guacamole protocol as a client, implementations of
+ HTTP and WebSocket-based tunnels, and mouse/keyboard/touch input
+ abstraction. Again, as the Guacamole protocol and all parts of the
+ architecture are documented here, you don't absolutely need to use these
+ objects, but it will make your life easier. Mouse and keyboard support in
+ JavaScript is finicky business, and the Guacamole client provided is
+ well-known to work with other components in the API, being the official
+ client of the project.
+
+That's really all there is to it.
+
+If you want authentication, the place to implement that would be in your
+extended version of `GuacamoleHTTPTunnelServlet`; this is what the Guacamole
+web application does. Besides authentication, there are many other things you
+could wrap around your remote desktop application, but ultimately the base of
+all this is simple: you have a tunnel which allows the JavaScript client to
+communicate with guacd, and you have the JavaScript client itself, with the
+hard part already provided within guacamole-common-js.
+
+(web-app-skeleton)=
+
+Web application skeleton
+------------------------
+
+As with most tutorials, this tutorial begins with creating a project skeleton
+that establishes a minimal base for the tutorial to enhance in subsequent
+steps.
+
+This tutorial will use Maven, which is the same build system used by the
+upstream Guacamole project. As the Guacamole project has a Maven repository for
+both the Java and JavaScript APIs, writing a Guacamole-based application using
+Maven is much easier; Maven will download and use the Guacamole API
+automatically.
+
+### `pom.xml`
+
+All Maven projects must have a project descriptor, the `pom.xml` file, in the
+root directory of the project. This file describes project dependencies and
+specific build requirements. Unlike other build tools like Apache Ant or GNU
+Autotools, Maven chooses convention over configuration: files within the
+project must be placed in specific locations, and the project dependencies must
+be fully described in the pom.xml. If this is done, the build will be handled
+automatically.
+
+The basis of this Guacamole-driven web application will be a simple HTML file
+which will ultimately become the client. While the finished product will have
+an HTTP tunnel written in Java, we don't need this yet for our skeleton. We
+will create a very basic, barebones Maven project containing only `index.html`
+and a web application descriptor file, `web.xml`. Once these files are in
+place, the project can be packaged into a `.war` file which can be deployed to
+your servlet container of choice (such as Apache Tomcat).
+
+As this skeleton will contain no Java code, it has no dependencies, and
+no build requirements beyond the metadata common to any Maven project.
+The `pom.xml` is thus very simple for the time being:
+i
+```xml
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.guacamole</groupId>
+ <artifactId>guacamole-tutorial</artifactId>
+ <packaging>war</packaging>
+ <version>1.3.0</version>
+ <name>guacamole-tutorial</name>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+</project>
+```
+
+### `WEB-INF/web.xml`
+
+Before the project will build, there needs to be a web application deployment
+descriptor, `web.xml`. This file is required by the Java EE standard for
+building the `.war` file which will contain the web application, and will be
+read by the servlet container when the application is actually deployed. For
+Maven to find and use this file when building the `.war`, it must be placed in
+the `src/main/webapp/WEB-INF/` directory.
+
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+
+<web-app version="2.5"
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
+
+ <!-- Basic config -->
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ </welcome-file-list>
+
+</web-app>
+```
+
+### `index.html`
+
+With the `web.xml` file in place and the skeleton `pom.xml` written, the web
+application will now build successfully. However, as the `web.xml` refers to a
+"welcome file" called `index.html` (which will ultimately contain our client),
+we need to put this in place so the servlet container will have something to
+serve. This file, as well as any other future static files, belongs within
+`src/main/webapp`.
+
+For now, this file can contain anything, since the other parts of our
+Guacamole-driven web application are not written yet. It is a placeholder which
+we will replace later:
+
+```html
+<!DOCTYPE HTML>
+<html>
+
+ <head>
+ <title>Guacamole Tutorial</title>
+ </head>
+
+ <body>
+ <p>Hello World</p>
+ </body>
+
+</html>
+```
+
+### Building the skeleton
+
+Once all three of the above files are in place, the web application will build,
+and can even be deployed to your servlet container. It won't do anything yet
+other than serve the `index.html` file, but it's good to at least try building
+the web application to make sure nothing is missing and all steps were followed
+correctly before proceeding:
+
+```console
+$ mvn package
+[INFO] Scanning for projects...
+[INFO] ------------------------------------------------------------------------
+[INFO] Building guacamole-tutorial
+[INFO] task-segment: [package]
+[INFO] ------------------------------------------------------------------------
+...
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD SUCCESSFUL
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 4 seconds
+[INFO] Finished at: Fri Jan 11 13:04:11 PST 2013
+[INFO] Final Memory: 18M/128M
+[INFO] ------------------------------------------------------------------------
+$
+```
+
+Assuming you see the "`BUILD SUCCESSFUL`" message when you build the web
+application, there will be a new file, `target/guacamole-tutorial-1.3.0.war`,
+which can be deployed to your servlet container and tested. If you changed the
+name or version of the project in the `pom.xml` file, the name of this new
+`.war` file will be different, but it can still be found within `target/`.
+
+(guacamole-skeleton)=
+
+Adding Guacamole
+----------------
+
+Once we have a functional web application built, the next step is to actually
+add the references to the Guacamole API and integrate a Guacamole client into
+the application.
+
+(adding-guac-to-pom)=
+
+### Updating `pom.xml`
+
+Now that we're adding Guacamole components to our project, we need to modify
+`pom.xml` to specify which components are being used, and where they can be
+obtained. With this information in place, Maven will automatically resolve
+dependencies and download them as necessary during the build.
+
+Regarding the build process itself, there are two main changes: we are now
+going to be using Java, and we need the JavaScript files from
+guacamole-common-js included automatically inside the `.war`.
+
+Guacamole requires at least Java 8, thus we must add a section to the
+`pom.xml` which describes the source and target Java versions:
+
+```xml
+ ...
+
+ <build>
+ <plugins>
+
+ <!-- Compile using Java 8 -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.3</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+
+ </plugins>
+
+ </build>
+
+ ...
+```
+
+Including the JavaScript files from an external project like
+guacamole-common-js requires using a feature of the maven war plugin called
+overlays. To add an overlay containing guacamole-common-js, we add a section
+describing the configuration of the Maven war plugin, listing
+guacamole-common-js as an overlay:
+
+```xml
+ ...
+
+ <build>
+ <plugins>
+
+ ...
+
+ <!-- Overlay guacamole-common-js (zip) -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <overlays>
+ <overlay>
+ <groupId>org.apache.guacamole</groupId>
+ <artifactId>guacamole-common-js</artifactId>
+ <type>zip</type>
+ </overlay>
+ </overlays>
+ </configuration>
+ </plugin>
+
+ </plugins>
+
+ </build>
+
+ ...
+```
+
+With the build now configured, we still need to add dependencies and list the
+repositories those dependencies can be downloaded from.
+
+As this is a web application which will use the Java Servlet API, we must
+explicitly include this as a dependency, as well as the Guacamole Java and
+JavaScript APIs:
+
+```xml
+ ...
+
+ <dependencies>
+
+ <!-- Servlet API -->
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Main Guacamole library -->
+ <dependency>
+ <groupId>org.apache.guacamole</groupId>
+ <artifactId>guacamole-common</artifactId>
+ <version>1.1.0</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <!-- Guacamole JavaScript library -->
+ <dependency>
+ <groupId>org.apache.guacamole</groupId>
+ <artifactId>guacamole-common-js</artifactId>
+ <version>1.3.0</version>
+ <type>zip</type>
+ <scope>runtime</scope>
+ </dependency>
+
+ </dependencies>
+
+ ...
+```
+
+The Java Servlet API will be provided by your servlet container, so Maven does
+not need to download it during the build, and it need not exist in any Maven
+repository.
+
+With these changes, the web application will still build at this point, even
+though no Java code has been written yet. You may wish to verify that
+everything still works.
+
+If the `pom.xml` was updated properly as described above, the web application
+should build successfully, and the Guacamole JavaScript API should be
+accessible in the `guacamole-common-js/` subdirectory of your web application
+after it is deployed. A quick check that you can access
+`/guacamole-tutorial-1.3.0/guacamole-common-js/all.min.js` is probably worth
+the effort.
+
+(simple-tunnel)=
+
+### The simplest tunnel possible
+
+As with the other tutorials in this book, we will keep this simple for the sake
+of demonstrating the principles behind a Guacamole-based web application, and
+to give developers a good idea of where to start looking when it's time to
+consult the API documentation.
+
+It is the duty of the class extending `GuacamoleHTTPTunnelServlet` to implement
+a function called `doConnect()`. This is the only function required to be
+implemented, and in general it is the only function you should implement; the
+other functions involved are already optimized for tunneling the Guacamole
+protocol.
+
+The `doConnect()` function returns a `GuacamoleTunnel`, which provides a
+persistent communication channel for `GuacamoleHTTPTunnelServlet` to use when
+talking with guacd and initiating a connection with some arbitrary remote
+desktop using some arbitrary remote desktop protocol. In our simple tunnel,
+this configuration will be hard-coded, and no authentication will be attempted.
+Any user accessing this web application will be immediately given a functional
+remote desktop, no questions asked.
+
+Create a new file, `TutorialGuacamoleTunnelServlet.java`, defining a basic
+implementation of a tunnel servlet class:
+
+```java
+package org.apache.guacamole.net.example;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.GuacamoleSocket;
+import org.apache.guacamole.net.GuacamoleTunnel;
+import org.apache.guacamole.net.InetGuacamoleSocket;
+import org.apache.guacamole.net.SimpleGuacamoleTunnel;
+import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+import org.apache.guacamole.servlet.GuacamoleHTTPTunnelServlet;
+
+public class TutorialGuacamoleTunnelServlet
+ extends GuacamoleHTTPTunnelServlet {
+
+ @Override
+ protected GuacamoleTunnel doConnect(HttpServletRequest request)
+ throws GuacamoleException {
+
+ // Create our configuration
+ GuacamoleConfiguration config = new GuacamoleConfiguration();
+ config.setProtocol("vnc");
+ config.setParameter("hostname", "localhost");
+ config.setParameter("port", "5901");
+ config.setParameter("password", "potato");
+
+ // Connect to guacd - everything is hard-coded here.
+ GuacamoleSocket socket = new ConfiguredGuacamoleSocket(
+ new InetGuacamoleSocket("localhost", 4822),
+ config
+ );
+
+ // Return a new tunnel which uses the connected socket
+ return new SimpleGuacamoleTunnel(socket);;
+
+ }
+
+}
+```
+
+Place this file in the `src/main/java/org/apache/guacamole/net/example`
+subdirectory of the project. The initial part of this subdirectory,
+`src/main/java`, is the path required by Maven, while the rest is the directory
+required by Java based on the package associated with the class.
+
+Once the class defining our tunnel is created, it must be added to the
+`web.xml` such that the servlet container knows which URL maps to it. This URL
+will later be given to the JavaScript client to establish the connection back
+to the Guacamole server:
+
+```xml
+ ...
+
+ <!-- Guacamole Tunnel Servlet -->
+ <servlet>
+ <description>Tunnel servlet.</description>
+ <servlet-name>Tunnel</servlet-name>
+ <servlet-class>
+ org.apache.guacamole.net.example.TutorialGuacamoleTunnelServlet
+ </servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Tunnel</servlet-name>
+ <url-pattern>/tunnel</url-pattern>
+ </servlet-mapping>
+
+ ...
+```
+
+The first section assigns a unique name, "Tunnel", to the servlet class we just
+defined. The second section maps the servlet class by it's servlet name
+("Tunnel") to the URL we wish to use when making HTTP requests to the servlet:
+`/tunnel`. This URL is relative to the context root of the web application. In
+the case of this web application, the final absolute URL will be
+`/guacamole-tutorial-1.3.0/tunnel`.
+
+(simple-client)=
+
+### Adding the client
+
+As the Guacamole JavaScript API already provides functional client and tunnel
+implementations, as well as mouse and keyboard input objects, the coding
+required for the "web" side of the web application is very minimal.
+
+We must create a `Guacamole.HTTPTunnel`, connect it to our
+previously-implemented tunnel servlet, and pass that tunnel to a new
+`Guacamole.Client`. Once that is done, and the `connect()` function of the
+client is called, communication will immediately ensue, and your remote desktop
+will be visible:
+
+```html
+ ...
+ <body>
+
+ <!-- Guacamole -->
+ <script type="text/javascript"
+ src="guacamole-common-js/all.min.js"></script>
+
+ <!-- Display -->
+ <div id="display"></div>
+
+ <!-- Init -->
+ <script type="text/javascript"> /* <![CDATA[ */
+
+ // Get display div from document
+ var display = document.getElementById("display");
+
+ // Instantiate client, using an HTTP tunnel for communications.
+ var guac = new Guacamole.Client(
+ new Guacamole.HTTPTunnel("tunnel")
+ );
+
+ // Add client to display div
+ display.appendChild(guac.getDisplay().getElement());
+
+ // Error handler
+ guac.onerror = function(error) {
+ alert(error);
+ };
+
+ // Connect
+ guac.connect();
+
+ // Disconnect on close
+ window.onunload = function() {
+ guac.disconnect();
+ }
+
+ /* ]]> */ </script>
+
+ </body>
+ ...
+```
+
+If you build and deploy the web application now, it will work, but mouse and
+keyboard input will not. This is because input is not implemented by the client
+directly. The `Guacamole.Client` object only decodes the Guacamole protocol and
+handles the display, providing an element which you can add manually to the
+DOM. While it will also send keyboard and mouse events for you, you need to
+call the respective functions manually. The Guacamole API provides keyboard and
+mouse abstraction objects which make this easy.
+
+We need only create a `Guacamole.Mouse` and `Guacamole.Keyboard`, and add event
+handlers to handle their corresponding input events, calling whichever function
+of the Guacamole client is appropriate to send the input event through the
+tunnel to guacd:
+
+```html
+ ...
+
+ <!-- Init -->
+ <script type="text/javascript"> /* <![CDATA[ */
+
+ ...
+
+ // Mouse
+ var mouse = new Guacamole.Mouse(guac.getDisplay().getElement());
+
+ mouse.onmousedown =
+ mouse.onmouseup =
+ mouse.onmousemove = function(mouseState) {
+ guac.sendMouseState(mouseState);
+ };
+
+ // Keyboard
+ var keyboard = new Guacamole.Keyboard(document);
+
+ keyboard.onkeydown = function (keysym) {
+ guac.sendKeyEvent(1, keysym);
+ };
+
+ keyboard.onkeyup = function (keysym) {
+ guac.sendKeyEvent(0, keysym);
+ };
+
+ /* ]]> */ </script>
+
+ ...
+```
+
+(next-steps)=
+
+Where to go from here
+---------------------
+
+At this point, we now have a fully functional Guacamole-based web application.
+This web application inherits all the core functionality present in the
+official Guacamole web application, including sound and video, without very
+much coding.
+
+Extending this application to provide authentication, multiple connections per
+user, or a spiffy interface which is compatible with mobile is not too much of
+a stretch. This is exactly how the Guacamole web application is written.
+Integrating Guacamole into an existing application would be similar.
+
diff --git a/tutorials/guacamole-auth-tutorial/pom.xml b/tutorials/guacamole-auth-tutorial/pom.xml
index 5aecdc3..1d6be79 100644
--- a/tutorials/guacamole-auth-tutorial/pom.xml
+++ b/tutorials/guacamole-auth-tutorial/pom.xml
@@ -17,14 +17,14 @@
<build>
<plugins>
- <!-- Written for 1.6 -->
+ <!-- Written for Java 8 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
- <source>1.6</source>
- <target>1.6</target>
+ <source>1.8</source>
+ <target>1.8</target>
</configuration>
</plugin>
diff --git a/tutorials/guacamole-tutorial/pom.xml b/tutorials/guacamole-tutorial/pom.xml
index bf85c5c..f5fe97e 100644
--- a/tutorials/guacamole-tutorial/pom.xml
+++ b/tutorials/guacamole-tutorial/pom.xml
@@ -17,14 +17,14 @@
<build>
<plugins>
- <!-- Compile using Java 1.6 -->
+ <!-- Compile using Java 8 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
- <source>1.6</source>
- <target>1.6</target>
+ <source>1.8</source>
+ <target>1.8</target>
</configuration>
</plugin>