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..6fb5d8f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ -/html -/book -/docbook-xsl +/build *~ diff --git a/Dockerfile b/Dockerfile index 7390cc2..f445230 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 # 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..39d2ceb 100644 --- a/Makefile +++ b/Makefile @@ -17,58 +17,31 @@ # 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") +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/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 +html: build/html/index.html -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) + sphinx-build -b html -d build/doctrees src/ build/html diff --git a/README b/README index c021f8d..ec617ec 100644 --- a/README +++ b/README @@ -18,68 +18,31 @@ snapshot copies of each release are included in the release archives: ------------------------------------------------------------ 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. +stack. It is written in reStructuredText, a plaintext markup syntax 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. +The build process involves running the Guacamole manual source through the +tooling provided by the Sphinx project, in particular "sphinx-build". ------------------------------------------------------------ Building the manual ------------------------------------------------------------ +1) Ensure Sphinx and the default ReadTheDocs theme are installed. These can be + installed using "pip" via the "sphinx" and "sphinx_rtd_theme" packages + respectively. -1) Ensure the DocBook XSL stylesheets are installed + https://pypi.org/project/Sphinx/ + https://pypi.org/project/sphinx-rtd-theme/ - 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 +2) 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 + The manual will now 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. ------------------------------------------------------------ @@ -90,9 +53,9 @@ 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. +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. @@ -117,15 +80,6 @@ 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 diff --git a/src/adding-protocol.rst b/src/adding-protocol.rst new file mode 100644 index 0000000..3569e88 --- /dev/null +++ b/src/adding-protocol.rst @@ -0,0 +1,872 @@ +.. _custom-protocols: + +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 ``make`` will + use when building. + +``Makefile.am`` + Used by GNU Automake and the ``configure`` script to generate the + ``Makefile`` which ``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 ``make``, and then install it (such that guacd can +find the plugin) by running ``make install`` and ``ldconfig`` as root: + +.. code-block:: 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 ``make`` is invoked, you will need to run the +``configure`` script, which will first need to be generated using +``autoreconf``: + +.. code-block:: 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 <#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: + + .. code-block:: 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 too 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: + +.. code-block:: c + + #include + + #include + + /* 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 +:ref:`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: + +.. container:: informalexample + + :: + + # 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 <#size-event-instruction>`__), we won't be doing that here +for the simplicity's sake: + +.. container:: informalexample + + :: + + #include + #include + #include + #include + + #include + + ... + + 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 <#server-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: + +.. container:: informalexample + + :: + + #ifndef BALL_H + #define BALL_H + + #include + + 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: + +.. container:: informalexample + + :: + + ... + + # 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: + +.. container:: informalexample + + :: + + #include "ball.h" + + #include + #include + #include + #include + #include + + #include + + ... + + 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: + +.. container:: informalexample + + :: + + ... + + #include + + #include + + 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: + +.. container:: informalexample + + :: + + #include "ball.h" + + #include + #include + #include + #include + #include + + #include + #include + + ... + + 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: + +.. container:: informalexample + + :: + + ... + + 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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + #include "ball.h" + + #include + #include + #include + #include + #include + #include + + #include + #include + + ... + + 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/adhoc-connections.rst b/src/adhoc-connections.rst new file mode 100644 index 0000000..1f89481 --- /dev/null +++ b/src/adhoc-connections.rst @@ -0,0 +1,160 @@ +.. _adhoc-connections: + +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 <#configuring-guacamole>`__\ *before +proceeding.* + +To install the extension, you must: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- 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: + +.. container:: informalexample + + `://:@:/? <://:@:/?>`__ + +The field can have any of the protocols supported by +Guacamole, as documented in `Configuring +Guacamole <#configuring-guacamole>`__. Many of the protocols define a +default value, with the exception of VNC. The 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.rst b/src/administration.rst new file mode 100644 index 0000000..4924d19 --- /dev/null +++ b/src/administration.rst @@ -0,0 +1,347 @@ +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 +`Database authentication <#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: + +.. image:: images/guacamole-settings-sections.png + :alt: Sections within the Guacamole 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. + +.. image:: images/manage-sessions.png + :alt: Session management interface + +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. + +.. image:: images/session-filter-example-1.png + +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. + +.. image:: images/session-filter-example-2.png + +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. + +.. image:: images/manage-history.png + :alt: Connection history interface + +.. _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 +--------------- + +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. + +.. image:: images/manage-users.png + :alt: User management interface + +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. + +.. image:: images/edit-user.png + :alt: Editing a user + +.. _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: + +.. image:: images/edit-user-membership.png + :alt: Editing group membership of a user + +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 +--------------------- + +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: + +.. image:: images/manage-groups.png + :alt: User group management interface + +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. + +.. image:: images/edit-user-group.png + :alt: Editing a user group + +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: + +.. image:: images/edit-group-memberships.png + :alt: Editing the various membership relations of a user group + +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. + +.. image:: images/manage-connections.png + :alt: Connection management interface + +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. + +.. image:: images/edit-connection.png + :alt: Editing a connection + +.. _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. + +.. image:: images/edit-group.png + :alt: Editing a connection group + +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 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: + +.. image:: images/edit-sharing-profile.png + :alt: Editing a sharing profile + 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 @@ - - - - - FAQ - - - - - - - Where does the name "Guacamole" come from? - - - - - The name was chosen arbitrarily from a random utterance in a conversation with - a member of the project. - - 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. - - 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". - - The name had a nice ring, we weren't embarrassed to use it, and it stuck. - - - - - - - - What does "clientless" mean? - - - - - 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. - - 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. - - - - - - - - Does Guacamole use WebSocket? - - - - 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. - - 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. - - - - - - - - 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? - - - - - You need to enable automatic flushing of the proxy's buffer as it receives - packets. - - 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. - - 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. - - In the case of mod_proxy, this option is flushpackets=on. - - - - - - - - I connect to the internet through a web proxy, and cannot connect to - Guacamole. I cannot reconfigure the proxy. How do I solve this? - - - - - You need to enable automatic flushing of your proxy's buffer to avoid - disrupting the stream used by Guacamole. - - 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. - - - - - - - - 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? - - - - - 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. - - - - - - - - Can I pay for custom Guacamole work, or for help integrating Guacamole into my - product, if the open source nature and licenses are preserved? - - - - - Yes. We love to be paid to work on Guacamole, especially if that work remains - open source. - - - - - - - - How can I contribute to the project? - - - - - 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. - - 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. - - - - - - - - How can I become an official member of the project? - - - - - The short answer is: "by being asked." - - 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. - - All that said, you do not need to be a member of the project to help out. Feel - free to contribute anything. - - - - - - - - I think I've found a bug. How do I report it? - - - - - The project tracks in-progress tasks and bugs via the JIRA instance hosted by - the Apache Software Foundation: - https://issues.apache.org/jira/browse/GUACAMOLE/ - 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. - - - - - - - - I need help! Where can I find some? - - - - - 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 mailing lists. You will need to subscribe prior to sending - email to any list. All mailing lists are actively filtered for - spam, and any email not originating from a subscriber will bounce. - There are two primary mailing lists: - - - user@guacamole.apache.org - - The user list is intended for general questions and discussions - which do not necessarily pertain to development. This list replaces - the old SourceForge forums used by Guacamole prior to its - acceptance into the Apache Software Foundation. - If you're not sure which mailing list to use, the user - list is probably the correct choice. - - - - dev@guacamole.apache.org - - The development list is for development-related discussion - involving people who are contributors to the Apache Guacamole - project (or who wish to become contributors). - - - - - - - - - - diff --git a/src/architecture.rst b/src/architecture.rst new file mode 100644 index 0000000..f5c88c5 --- /dev/null +++ b/src/architecture.rst @@ -0,0 +1,152 @@ +.. _guacamole-architecture: + +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/book.xslt b/src/book.xslt deleted file mode 100644 index 095ae44..0000000 --- a/src/book.xslt +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - - - - 7in - 9.1875in - - - 1.25in - 1.00in - 0.75in - 0.75in - - 1 - - - 0pt - - - Nimbus Sans L - Nimbus Roman No9 L - DejaVu Sans Mono - - - - - - 0.75em - 1em - - - - - - - - - auto - always - - - - - - - - - #E0E0E0 - 0.5pt - solid - #575757 - 3pt - - - - - - - 0 - 1 - 0 - ansi - - - no - - - 0 - 1 - images/ - .png - - - - 0.75in - - - - - 1pt solid black - 0.5in - - - - 48pt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - center - - - diff --git a/src/cas-auth.rst b/src/cas-auth.rst new file mode 100644 index 0000000..0ea2875 --- /dev/null +++ b/src/cas-auth.rst @@ -0,0 +1,139 @@ +.. _cas-auth: + +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 <#configuring-guacamole>`__\ *before +proceeding.* + +To install the CAS authentication extension, you must: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- Copy ``guacamole-auth-cas-1.3.0.jar`` within + ``GUACAMOLE_HOME/extensions``. + +- 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 @@ - - - Adding new protocols - - protocols - implementing - - 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 - make will use when building. - - - - Makefile.am - - Used by GNU Automake and the configure script to generate - the Makefile which 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 - make, and then install it (such that guacd can find the plugin) by - running make install and ldconfig as root: - - $ 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 make is invoked, you will need to run the - configure script, which will first need to be generated using - autoreconf: - - $ 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 . - - 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. 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: - - $ ./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. - -
- Minimal skeleton client - Very little needs too 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: - - #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 ). - 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. -
-
- 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), or even - updated when the window size changes (provided by the user via "size" - instructions), we won't be doing that here for the simplicity's sake: - - #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: - - - Send a "size" instruction, initializing the - display size to 1024x768. - - - Draw a 1024x768 gray rectangle over the display using the "rect" and "cfill" instructions. - - - Send a "sync" instruction, informing the - remote display that a frame has been completed. - - - 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. -
-
- 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: - - #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: - - #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). -
-
- 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: - - ... - -#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: - - #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, 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: - - ... - -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. -
-
- 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: - - 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. -
-
- 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: - - #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/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 @@ - - - - Ad-hoc Connections - - connections - adhoc - - - adhoc - - - quickconnect - - 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. - - 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. - - -
- 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 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 before - proceeding. - To install the extension, you must: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - Place the guacamole-auth-quickconnect-1.3.0.jar file in - the GUACAMOLE_HOME/extensions directory. - - -
- Configuring Guacamole for the quickconnect extension - - configuring quickconnect - - 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 - 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 - 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 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 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: - - protocol://username:password@host:port/?parameters - - The protocol field can have any of the protocols supported - by Guacamole, as documented in . 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/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 @@ - - - - Administration - - 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 . - 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: - - - - - - - Sections within the Guacamole settings screen. - - - - Clicking any of these options will take you to a corresponding management section where - you can perform administrative tasks. -
- Managing sessions - - session management - - 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. - - - - - - - - Session management interface - - - - - 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 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 - - history - - - 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. - - - - - - - - Connection history interface - - - - -
- 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. - - - - - - - - User management interface - - - - - 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. - - - - - - - - Editing a user - - - - -
- 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: - - - - - - - - Editing group membership of a user - - - - - 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 - - - user groups - - - groups - - 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: - - - - - - - - User group management interface - - - - - 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. - - - - - - - - Editing a user group - - - - -
- 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, with a - corresponding section dedicated to each within the user group editor: - - - - - - - - Editing the various membership relations of a user group - - - - - 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 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. -
-
-
- Connections and connection groups - - connection management - - - connection groups - - - 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 or a user group that the user is a member of, - checking the box corresponding to the connection or connection group you created. - - - - - - - - Connection management interface - - - - - 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. - - - - - - - - Editing a connection - - - - -
- 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. - - session affinity - 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. - - - - - - - - Editing a connection group - - - - -
-
- 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, even if - those users do not otherwise have user accounts within Guacamole. - The name of the sharing profile will be presented an option within the 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. - - The only extension which ships with Guacamole and implements enough - of the Guacamole extension API to share its - connections is the database authentication extension. - 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, 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 and the list of - connections in the user editor. - 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: - - - - - - - - Editing a sharing profile - - - - -
-
-
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 @@ - - - Implementation and architecture - - history - - - architecture - - - implementation - - 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. - - - - - - - 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. -
- The Guacamole protocol - - Guacamole protocol - - - 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 - - - client plugin - - 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. - - libguac - relationship with guacd - - guacd and all client plugins depend on a common library, libguac, which makes - communication via the Guacamole protocol easier and a bit more abstract. -
-
- The web application - - 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 - - history - - 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. -
-
- 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/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 @@ - - - - CAS Authentication - - 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. - -
- 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 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 before - proceeding. - To install the CAS authentication extension, you must: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - Copy guacamole-auth-cas-1.3.0.jar within - GUACAMOLE_HOME/extensions. - - - Configure Guacamole to use CAS authentication, as described - below. - - -
- Configuring Guacamole for CAS Authentication - - configuring CAS authentication - - - CAS authentication - configuration - - 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 - 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 - 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 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. -
-
- 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/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 @@ - - - - - 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: - - - Sufficient for small deployments of Guacamole. - - - 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. -
- <varname>GUACAMOLE_HOME</varname> (<filename>/etc/guacamole</filename>) - - GUACAMOLE_HOME - - 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 <varname>GUACAMOLE_HOME</varname> - 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: - - - 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. - - - 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. - - - Specifying the full path to an alternative directory with the system - property guacamole.home. - - -
-
- -
- <filename>guacamole.properties</filename> - - guacamole.properties - - - configuration - - 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: - - - Within GUACAMOLE_HOME, as defined above. - - - 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 - 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 - 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. - - - - - allowed-languages - 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 - 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 - guacd-hostname - - The host the Guacamole proxy daemon (guacd) is - listening on. If omitted, Guacamole will assume guacd is - listening on localhost. - - - - - guacd-port - 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 - 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 - 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. - - - - - Example <filename>guacamole.properties</filename> - # Hostname and port of guacamole proxy -guacd-hostname: localhost -guacd-port: 4822 - -
-
- Logging within the web application - - logging - - 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: - - - - logging - errors - 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. - - - - - logging - warnings - warn - - Warnings are generally non-fatal conditions. The operation continued, but - encountered noteworthy problems. - - - - - logging - info - 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. - - - - - logging - debug - 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. - - - - - logging - trace - 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 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: - - <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 is provided on the Logback project's web site. -
-
- Using the default authentication - - 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. -
- <filename>user-mapping.xml</filename> - - 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: - <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. -
- Adding users - - users - adding - - When using - BasicFileAuthenticationProvider, - 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: - <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: - <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. -
-
- Adding connections to a user - - connections - adding - - 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. -
-
-
-
- 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 - - 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. -
- 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. - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - hostname - - - VNC - hostname - The hostname or IP address of the VNC server - Guacamole should connect to. - - - - port - - - VNC - 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 - - - VNC - retrying connections - 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. - - - - - -
-
- 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. - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - username - - - VNC - username - The username to use when attempting - authentication, if any. This parameter is optional. - - - - password - - - VNC - password - The password to use when attempting - authentication, if any. This parameter is optional. - - - - - -
-
- 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. - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - color-depth - - - VNC - 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 - - - VNC - mouse pointer - 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 - - - VNC - 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 - - - VNC - 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 - - - VNC - lossless compression - 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. - - - - - -
-
- Session recording - 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 guacenc utility provided with - guacamole-server. - For example, to produce a video called "NAME.m4v" - from the recording "NAME", you would run: - - $ guacenc /path/to/recording/NAME - - The guacenc utility has additional options for overriding - default behavior, including tweaking the output format, which are documented in - detail within the manpage: - - $ 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 guaclog utility. The usage of - guaclog is analogous to guacenc, and - results in the creation of a new text file containing the interpreted - events: - - $ 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. -$ - - - 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. - - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - recording-path - - - VNC - graphical recording - 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 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. - - - - - -
-
- File transfer (via SFTP) - 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 . - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - enable-sftp - - - VNC - file transfer - - 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 - VNC server specified with the - hostname parameter 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 should be that of a single - entry from an OpenSSH known_hosts - file. - For more information, please see . - - - - sftp-username - - The username to authenticate as when connecting to the - specified SSH server for SFTP. This parameter is - required. - - - - 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 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. - - - - - -
-
- 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. - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - dest-host - - repeater - VNC - - proxy - VNC - - VNC - repeater - 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 - - repeater - VNC - - proxy - VNC - 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. - - - - -
-
- 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. - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - reverse-connect - - - VNC - reverse connection - 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 - - - VNC - 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). - - - - - -
-
- 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 netstat: - - $ 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: - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - enable-audio - - - VNC - sound - - VNC - PulseAudio - 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. - - - - - -
-
- 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. - - 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. - - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - clipboard-encoding - - - clipboard encoding - - VNC - clipboard encoding - The encoding to assume for the VNC clipboard. - This parameter is optionl. 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. - - - - - - - - -
-
- Disabling clipboard access - Guacamole provides bidirectional access to the clipboard by default for VNC - connections. This behavior can be overridden on a per-connection basis with the - disable-copy and disable-paste - parameters. - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - disable-copy - - - disable clipboard - - VNC - disable clipboard - 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. - - - - disable-paste - - - disable clipboard - - VNC - disable clipboard - 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. - - - - - -
-
- Wake-on-LAN Configuration - 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. - - - 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. - - - - parameters - VNC - - - - - - - Parameter name - Description - - - - - wol-send-packet - - - wol-send-packet - - VNC - 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 - - - wol-mac-addr - - VNC - 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 - - - wol-broadcast-addr - - VNC - 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 - - - wol-udp-port - - VNC - 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 - - - wol-wait-time - - VNC - 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. - - - - - - -
-
- Adding a VNC connection - - VNC - adding - - 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: - <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. -
-
- Which VNC server? - - VNC servers - - 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 or TigerVNC - - RealVNC - - - 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 - - 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 - - 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 - - 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 or KVM - - QEMU - - - 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 - - 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. -
- 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. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - hostname - - - RDP - hostname - The hostname or IP address of the RDP server - Guacamole should connect to. - - - - port - - - RDP - 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. - - - - - -
-
- 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 and - - LDAP support. 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. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - username - - - RDP - username - The username to use to authenticate, if any. - This parameter is optional. - - - - password - - - RDP - password - The password to use when attempting - authentication, if any. This parameter is optional. - - - - domain - - - RDP - domain - The domain to use when attempting - authentication, if any. This parameter is optional. - - - - security - - - RDP - security - - RDP - NLA - - RDP - TLS - 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" 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 - - 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. - - - - - - - ignore-cert - - - RDP - ignoring certificates - 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 - - - RDP - disabling authentication - 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. - - - - - -
-
- 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. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - client-name - - - RDP - 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 - - - RDP - console - If set to "true", you will be connected to the - console (admin) session of the RDP server. - - - - initial-program - - - RDP - initial program - The full path to the program to run immediately - upon connecting. This parameter is optional. - - - - server-layout - - - keyboard layout - - RDP - keyboard 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: - - - en-us-qwerty - - English (US) keyboard - - - - en-gb-qwerty - - English (UK) keyboard - - - - de-ch-qwertz - - Swiss German keyboard (qwertz) - - - - de-de-qwertz - - German keyboard (qwertz) - - - - fr-be-azerty - - Belgian French keyboard (azerty) - - - - fr-fr-azerty - - French keyboard (azerty) - - - - fr-ch-qwertz - - Swiss French keyboard (qwertz) - - - - hu-hu-qwertz - - Hungarian keyboard (qwertz) - - - - it-it-qwerty - - Italian keyboard - - - - ja-jp-qwerty - - Japanese keyboard - - - - pt-br-qwerty - - Portuguese Brazilian keyboard - - - - es-es-qwerty - - Spanish keyboard - - - - es-latam-qwerty - - Latin American keyboard - - - - sv-se-qwerty - - Swedish keyboard - - - - tr-tr-qwerty - - Turkish-Q keyboard - - - - failsafe - - Unknown keyboard - this option sends only - Unicode events and should work for any keyboard, - though not necessarily all RDP servers or - applications. - If your server's keyboard layout is not yet - supported, this option should work in the - meantime. - - - - - - - timezone - - - RDP - 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. - - - - - -
-
- 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. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - color-depth - - - RDP - 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 - - - RDP - display size - 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 - - - RDP - display resolution - 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 - - - RDP - display size - 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 - - - RDP - lossless compression - 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. - - - - - -
-
- Session recording - 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 guacenc utility provided with - guacamole-server. - For example, to produce a video called "NAME.m4v" - from the recording "NAME", you would run: - - $ guacenc /path/to/recording/NAME - - The guacenc utility has additional options for overriding - default behavior, including tweaking the output format, which are documented in - detail within the manpage: - - $ 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 guaclog utility. The usage of - guaclog is analogous to guacenc, and - results in the creation of a new text file containing the interpreted - events: - - $ 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. -$ - - - 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. - - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - recording-path - - - RDP - graphical recording - 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 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. - - - - - -
-
- 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 SSH - connection, users will be able to upload and download files as described in - . - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - disable-audio - - disabling audio - - audio - - RDP - 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 - - - enabling audio input - - audio input - - RDP - 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 - - - enabling printing - - printing - - RDP - 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 - - - enabling file transfer - - file transfer - - RDP - file transfer - 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 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. - 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 - - - RDP - 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. - - - - - -
-
- Preconnection PDU (Hyper-V / VMConnect) - - 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" 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: - - 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: - - - 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). - - - If necessary, set "ignore-cert" to - "true". Hyper-V may use a self-signed - certificate. - - - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - preconnection-id - - - 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 - - - preconnection BLOB - - Hyper-V - 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. - - - - - -
-
- Remote desktop gateway - - remote desktop gateway - - TS 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. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - gateway-hostname - - - 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 - - - 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 - - - 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 - - - gateway password - The password to provide when authenticating with - the remote desktop gateway, if a gateway is being - used. - - - - gateway-domain - - - 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. - - - - - -
-
- Load balancing and RDP connection brokers - - load balancing - - connection broker - 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. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - load-balance-info - - - loadbalanceinfo - 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 + SFTP - 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 . - 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. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - enable-sftp - - - RDP - file transfer - - 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 - RDP server specified with the - hostname parameter 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 . - - - - 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 RDP connection. If omitted, - the value provided for the username - parameter will be use. - - - - 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 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. - - - - - -
-
- Disabling clipboard access - Guacamole provides bidirectional access to the clipboard by default for RDP - connections. This behavior can be overridden on a per-connection basis with the - disable-copy and disable-paste - parameters. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - disable-copy - - - disable clipboard - - RDP - disable clipboard - 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. - - - - disable-paste - - - disable clipboard - - RDP - disable clipboard - 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. - - - - - -
-
- 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. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - enable-wallpaper - - - RDP - 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 - - - RDP - theming - If set to "true", enables use of theming of - windows and controls. By default, theming within RDP - sessions is disabled. - - - - enable-font-smoothing - - - RDP - font smoothing - - RDP - ClearType - 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 - - - RDP - 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 - - - RDP - desktop composition - - RDP - Aero - 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 - - - RDP - menu animations - If set to "true", menu open and close animations - will be allowed. Menu animations are disabled by - default. - - - - disable-bitmap-caching - - - RDP - 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 - offscreen bitmap caching - 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. - - - - disable-glyph-caching - - - RDP - 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. - - - - - -
-
- 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. - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - remote-app - - - RemoteApp - 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. - - - - - -
-
- Wake-on-LAN Configuration - 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. - - - 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. - - - - parameters - RDP - - - - - - - Parameter name - Description - - - - - wol-send-packet - - - wol-send-packet - - RDP - 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 - - - wol-mac-addr - - RDP - 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 - - - wol-broadcast-addr - - RDP - 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 - - - wol-udp-port - - RDP - 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 - - - wol-wait-time - - RDP - 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. - - - - - - -
-
- Adding an RDP connection - - RDP - adding - - 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: - <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 - - 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. -
- 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. -
-
- 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. - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - hostname - - - SSH - hostname - The hostname or IP address of the SSH server - Guacamole should connect to. - - - - port - - - SSH - 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 - - - SSH - 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 . - - - - server-alive-interval - - - - SSH - 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. - - - - - - -
-
- 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. - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - username - - - SSH - 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 - - - SSH - 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 - - - SSH - public key authentication - 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 ssh-keygen utility. - - - - passphrase - - - SSH - 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. - - - - - -
-
- Display settings - 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, - 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. - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - color-scheme - - - SSH - color scheme - 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: - - 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. - - - - 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: - - - 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. - - - - 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 - - - SSH - font - 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. - - - - - -
-
- 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. - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - command - - - SSH - 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. - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - locale - - - SSH - 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 - - - - SSH - 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. - - - - - - -
-
- 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. - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - backspace - - - SSH - 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 - - - SSH - terminal type - This parameter sets the terminal emulator type - string that is passed to the SSH server. This parameter is - optional. If not specified, "linux" - is used as the terminal emulator type by default. - - - - - -
- Providing input directly from JavaScript - 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 createPipeStream() function of Guacamole.Client: - - var outputStream = client.createPipeStream('text/plain', 'STDIN'); - - The resulting Guacamole.OutputStream can then be - used to stream data directly to the input of the SSH session, as if typed by - the user: - - // 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(); - -
-
-
- 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: - NAME, which contains the - raw text data, and 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 - script command, and can be replayed using - scriptreplay (if installed). For example, to replay a - typescript called "NAME", you would run: - - $ scriptreplay NAME.timing NAME - - - 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. - - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - typescript-path - - - SSH - typescripts - - SSH - text recording - 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: - NAME, - which contains the raw text data, and - 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. - - - - - -
-
- Graphical session recording - 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 guacenc utility - provided with guacamole-server. - For example, to produce a video called "NAME.m4v" - from the recording "NAME", you would run: - - $ guacenc /path/to/recording/NAME - - The guacenc utility has additional options for overriding - default behavior, including tweaking the output format, which are documented in - detail within the manpage: - - $ 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 guaclog utility. The usage of - guaclog is analogous to guacenc, and - results in the creation of a new text file containing the interpreted - events: - - $ 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. -$ - - - 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. - - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - recording-path - - - SSH - graphical recording - 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 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. - - - - - -
-
- 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 - . - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - enable-sftp - - - SSH - file transfer - - 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 - 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. 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. - - - - - -
-
- Disabling clipboard access - 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 disable-copy and - disable-paste parameters. - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - disable-copy - - - disable clipboard - - SSH - disable clipboard - 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. - - - - disable-paste - - - disable clipboard - - SSH - disable clipboard - 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. - - - - - -
-
- Wake-on-LAN Configuration - 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. - - - 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. - - - - parameters - SSH - - - - - - - Parameter name - Description - - - - - wol-send-packet - - - wol-send-packet - - SSH - 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 - - - wol-mac-addr - - SSH - 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 - - - wol-broadcast-addr - - SSH - 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 - - - wol-udp-port - - SSH - 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 - - - wol-wait-time - - SSH - 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. - - - - - - -
-
- Adding an SSH connection - - SSH - adding - - 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: - <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 - - 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. -
- 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. - - - parameters - telnet - - - - - - - Parameter name - Description - - - - - hostname - - - telnet - hostname - The hostname or IP address of the telnet server - Guacamole should connect to. - - - - port - - - telnet - 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. - - - - - -
-
- 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 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). - - - parameters - telnet - - - - - - - Parameter name - Description - - - - - username - - - telnet - 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 - - - telnet - 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). - - - - - -
-
- Display settings - 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, - 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. - - - parameters - telnet - - - - - - - Parameter name - Description - - - - - color-scheme - - - telnet - color scheme - 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: - - 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. - - - - 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: - - - 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. - - - - 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 - - - telnet - font - 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. - - - - - -
-
- 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. - - - parameters - telnet - - - - - - - Parameter name - Description - - - - - backspace - - - telnet - 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 - - - telnet - terminal type - This parameter sets the terminal emulator type - string that is passed to the telnet server. This parameter - is optional. If not specified, - "linux" is used as the terminal - emulator type by default. - - - - - -
- Providing input directly from JavaScript - 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 createPipeStream() function of Guacamole.Client: - - var outputStream = client.createPipeStream('text/plain', 'STDIN'); - - The resulting Guacamole.OutputStream can then be - used to stream data directly to the input of the telnet session, as if typed - by the user: - - // 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(); - -
-
-
- Text session recording (typescripts) - 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 typescript-path: - NAME, which contains the - raw text data, and 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 - script command, and can be replayed using - scriptreplay (if installed). For example, to replay a - typescript called "NAME", you would run: - - $ scriptreplay NAME.timing NAME - - - 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. - - - - parameters - telnet - - - - - - - Parameter name - Description - - - - - typescript-path - - - telnet - typescripts - - telnet - text recording - 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: - NAME, - which contains the raw text data, and - 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. - - - - - -
-
- Graphical session recording - 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 guacenc utility - provided with guacamole-server. - For example, to produce a video called "NAME.m4v" - from the recording "NAME", you would run: - - $ guacenc /path/to/recording/NAME - - The guacenc utility has additional options for overriding - default behavior, including tweaking the output format, which are documented in - detail within the manpage: - - $ 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 guaclog utility. The usage of - guaclog is analogous to guacenc, and - results in the creation of a new text file containing the interpreted - events: - - $ 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. -$ - - - 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. - - - - parameters - telnet - - - - - - - Parameter name - Description - - - - - recording-path - - - telnet - graphical recording - 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 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. - - - - - -
-
- Disabling clipboard access - 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 disable-copy and - disable-paste parameters. - - - parameters - telnet - - - - - - - Parameter name - Description - - - - - disable-copy - - - disable clipboard - - telnet - disable clipboard - 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. - - - - disable-paste - - - disable clipboard - - telnet - disable clipboard - 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. - - - - - -
-
- Wake-on-LAN Configuration - 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. - - - 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. - - - - parameters - telnet - - - - - - - Parameter name - Description - - - - - wol-send-packet - - - wol-send-packet - - telnet - 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 - - - wol-mac-addr - - telnet - 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 - - - wol-broadcast-addr - - telnet - 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 - - - wol-udp-port - - telnet - 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 - - - wol-wait-time - - telnet - 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. - - - - - - -
-
- Adding a telnet connection - - telnet - adding - - 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: - <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 - - 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. -
- 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. - - - parameters - Kubernetes - - - - - - - Parameter name - Description - - - - - hostname - - - Kubernetes - hostname - The hostname or IP address of the Kubernetes - server that Guacamole should connect to. - - - - port - - - Kubernetes - 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 - - - Kubernetes - 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 - - - Kubernetes - pod - The name of the Kubernetes pod containing with - the container being attached to. - - - - container - - - Kubernetes - 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 - - - Kubernetes - 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 kubectl - exec. When omitted, the behavior is analogous - to running kubectl attach. - - - - - -
-
- 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. - - - parameters - Kubernetes - - - - - - - Parameter name - Description - - - - - 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. - - - - - -
-
- Display settings - 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, 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. - - - parameters - Kubernetes - - - - - - - Parameter name - Description - - - - - color-scheme - - - Kubernetes - color scheme - 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: - - 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. - - - - 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: - - - 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. - - - - 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 - - - Kubernetes - font - 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. - - - - read-only - - - Kubernetes - 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 console of the Kubernetes - container. This parameter is optional. - If omitted, the connection will not be read-only. - - - - scrollback - - - Kubernetes - 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. - - - - - -
-
- 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. - - - parameters - Kubernetes - - - - - - - Parameter name - Description - - - - - backspace - - - Kubernetes - 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 - - - Kubernetes - terminal type - This parameter sets the terminal emulator type - string that is passed to the Kubernetes server. This - parameter is optional. If not specified, - "linux" is used as the terminal - emulator type by default. - - - - - -
-
- Text session recording (typescripts) - 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 typescript-path: - NAME, which contains the - raw text data, and 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 - script command, and can be replayed using - scriptreplay (if installed). For example, to replay a - typescript called "NAME", you would run: - - $ scriptreplay NAME.timing NAME - - - 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. - - - - parameters - Kubernetes - - - - - - - Parameter name - Description - - - - - typescript-path - - - Kubernetes - typescripts - - Kubernetes - text recording - 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: - NAME, - which contains the raw text data, and - 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. - - - - - -
-
- Graphical session recording - 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 guacenc utility - provided with guacamole-server. - For example, to produce a video called "NAME.m4v" - from the recording "NAME", you would run: - - $ guacenc /path/to/recording/NAME - - The guacenc utility has additional options for overriding - default behavior, including tweaking the output format, which are documented in - detail within the manpage: - - $ 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 guaclog utility. The usage of - guaclog is analogous to guacenc, and - results in the creation of a new text file containing the interpreted - events: - - $ 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. -$ - - - 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. - - - - parameters - Kubernetes - - - - - - - Parameter name - Description - - - - - recording-path - - - Kubernetes - graphical recording - 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 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. - - - - - -
-
- Adding a Kubernetes connection - - Kubernetes - adding - - 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: - <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. -
-
-
- Parameter tokens - - 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 ${TOKEN_NAME} or - ${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 "$${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 - - tokens - 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 - ${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-specific tokens - - tokens - extension-specific - - 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 Extension Tokens - - tokens - cas - - 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 Extension Tokens - - tokens - ldap - - 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 - - parameters - prompt - 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. - - - 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. - -
-
-
- 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: - - - If the value contains no special characters, just include it as-is. - - - If the value contains any special characters (whitespace, newlines, - #, \, or "), enclose the entire value - within double quotes. - - - If the value is enclosed within double quotes, escape newlines, - \, and " with a backslash. - - - - guacd.conf parameters - - parameters - guacd.conf - - - - - - - - Section - Name - Description - - - - - daemon - pid_file - - - 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. - - - - daemon - log_level - - - logging - guacd - - guacd - logging - - 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. - - - - server - bind_host - - - 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. - - - - server - bind_port - - - bind_port - The port that guacd should bind to when listening for - connections. If unspecified, port 4822 will be used. - - - - ssl - server_certificate - - - 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. - - - - ssl - server_key - - - 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. - - - - -
- You can also affect the configuration of guacd with command-line options. If given, - these options take precendence over the system-wide configuration file: - - - - - Changes the host or address that guacd listens on. - This corresponds to the bind_host parameter within - the server section of - guacd.conf. - - - - - - 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. - - - - - - 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. - - - - - - 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. - - - - - - 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: - - - - - 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. - - - - - - 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. - - - -
- -
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 @@ - - - - Custom authentication - - authentication - custom - - 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. -
- 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. -
-
- 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. - - Barebones <filename>pom.xml</filename> required for a simple authentication - extension. - <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> - - 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. - - A skeleton <classname>TutorialAuthenticationProvider</classname> - 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 . 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. - - The required <filename>guac-manifest.json</filename> - { - - "guacamoleVersion" : "1.3.0", - - "name" : "Tutorial Authentication Extension", - "namespace" : "guac-auth-tutorial", - - "authProviders" : [ - "org.apache.guacamole.auth.TutorialAuthenticationProvider" - ] - -} - -
-
- 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 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: - - $ 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/. -
-
- 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. - - <filename>TutorialProperties.java</filename>, a class containing property - definitions - 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. - - Properties describing a user and connection, as required by this tutorial - # 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. - - Checking the credentials against the properties - @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. -
-
- 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. - - Parsing and returning a <classname>GuacamoleConfiguration</classname> - @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 . -
-
- 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 , - 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/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 @@ - - - Installing Guacamole with Docker - - 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. -
- Running the <package>guacd</package> 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. -
- Running <package>guacd</package> 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. - - $ 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). - - $ docker run -e GUACD_LOG_LEVEL=debug -d guacamole/guacd - -
-
- Running <package>guacd</package> 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. - - 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. - - - $ 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. -
-
-
- 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. - - If using PostgreSQL or 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 - http://HOSTNAME:8080/guacamole/, where - HOSTNAME is the hostname or address of the machine - hosting Docker. -
- 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 - . - -
-
- Connecting Guacamole to <package>guacd</package> - 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: - - $ 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: - - - - - - - Variable - Description - - - - - 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_PORT - - 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: - $ 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, PostgreSQL, and 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. -
-
- 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 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 : - - $ 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: - - - Create a database for Guacamole within MySQL, such as - guacamole_db. - - - Create a user for Guacamole within MySQL with access to this database, - such as - guacamole_user. - - - Run the script on the newly-created database. - - - The process for doing this via the mysql utility included - with MySQL is documented in . -
-
- 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: - - $ 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: - - - - - - - Variable - Description - - - - - 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: - - $ 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 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 . -
-
- 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: - - - - - - - Variable - Description - - - - - 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. -
-
- 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: - - - - - - - Variable - Description - - - - - 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. - - - - - -
-
-
- 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 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 : - - $ 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: - - - Create a database for Guacamole within PostgreSQL, such as - guacamole_db. - - - Run the script on the newly-created database. - - - 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 psql and - createdb utilities included with PostgreSQL is documented - in . -
-
- 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: - - $ 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: - - - - - - - Variable - Description - - - - - 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: - - $ 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 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 . -
-
- 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: - - - - - - - Variable - Description - - - - - 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. -
-
- 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: - - - - - - - Variable - Description - - - - - 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: - - - - - - - Variable - Description - - - - - 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. - - - - - - -
-
-
- 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: - - - - - - - Variable - Description - - - - - 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: - - $ 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 option above) is not required. Similar to LDAP, the - connection information for guacd can be specified using - environment variables, as described in . -
- 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: - - - - - - - Variable - Description - - - - - 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. -
-
- 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: - - - - - - - Variable - Description - - - - - 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 , 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. -
-
-
- 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: - - - - - - - Variable - Description - - - - - 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. - - - - - -
-
- Custom extensions and <envar>GUACAMOLE_HOME</envar> - 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: - - - - - - - Variable - Description - - - - - 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. 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 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 - 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: - - $ docker run --name some-guacamole \ - ... - -v /local/path:/some-directory \ - -e GUACAMOLE_HOME=/some-directory \ - -d -p 8080:8080 guacamole/guacamole - -
-
- Verifying the Guacamole install - Once the Guacamole image is running, Guacamole should be accessible at - http://HOSTNAME:8080/guacamole/, where - HOSTNAME is the hostname or address of the machine - hosting Docker, and you should 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: - - $ docker logs some-guacamole - -
-
-
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 @@ - - - - Duo two-factor authentication - - Duo - - 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. - - 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 before proceeding. - -
- 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. -
-
- 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 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: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - Copy guacamole-auth-duo-1.3.0.jar within - GUACAMOLE_HOME/extensions. - - - Configure Guacamole to use Duo authentication, as described below. - - - - 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: - - - - - - - -
-
- Configuring Guacamole for Duo - - configuring Duo - - - Duo - configuration - - 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: - - $ 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: - - $ dd if=/dev/random count=1 | sha256sum -5d16d6bb86da73e7d1abd3286b21dcf3b3e707532e64ceebc7a008350d0d485d - -$ - -
-
- 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. - - - 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/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 @@ - - - - Event listeners - - events - 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. -
- 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. - - Barebones <filename>pom.xml</filename> required for a simple listener - extension that writes log messages for received events. - <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> - - 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. - - A skeleton <classname>TutorialListener</classname> - 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 . 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. - - The required <filename>guac-manifest.json</filename> - { - - "guacamoleVersion" : "1.3.0", - - "name" : "Tutorial Listener Extension", - "namespace" : "guac-listener-tutorial", - - "listeners" : [ - "org.apache.guacamole.event.TutorialListener" - ] - -} - -
-
- 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. - - $ 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 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/. -
-
- 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. - - Using the event type to log an authentication success or failure - 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 - and installed as described below in . -
-
- 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 "blacklist" 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. - - Vetoing an event by throwing a <classname>GuacamoleException</classname> - 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()); - } - } - -} - - 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. -
-
- 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 , - 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/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 @@ - - - guacamole-common-js - - API - JavaScript - - - 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: - - 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: - - 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. - - 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. - - 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: - - 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. -
- 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 response. to true mouse - events. Mouse events which are actually the result of touch - events are ignored. - - 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. -
-
- 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. - - 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. -
-
- 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. - - 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: - - <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 the keyboard - Once you have a keyboard layout available, adding an on-screen - keyboard to your application is simple: - - // 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. - - - - guac-keyboard-requires-MODIFIER - - Added to the cap element when that cap requires a - specific modifier. - - - - guac-keyboard-uses-MODIFIER - - Added to the key element when any cap contained - within it requires a specific modifier. - - - - 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. - - - - - 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. - -
-
- 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. - - // 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/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 @@ - - - <package>guacamole-common</package> - - API - Java - - - 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. -
- 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 translated 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 created 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: - - 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); - - } - -} - -
-
- 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. -
- <classname>GuacamoleReader</classname> - 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. -
-
- <classname>GuacamoleWriter</classname> - 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/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 @@ - - - guacamole-ext - - API - Java - - - 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: - - - Provide alternative authentication methods and sources of connection/user - data. - - - Provide event listeners that will be notified as Guacamole performs tasks such - as authentication and tunnel connection. - - - Theme or brand Guacamole through additional CSS files and static resources. - - - Extend Guacamole's JavaScript code by providing JavaScript that will be loaded - automatically. - - - Add additional display languages, or alter the translation strings of existing - languages. - - -
- 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. -
- 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: - - - - - - - Property - Description - - - - - 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 ...> - 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 - 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: - - { - "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: - - { - - "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" - } - -} - -
-
- 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: - - <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: - - - - - - - Name - Description - - - - - 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: - - <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. -
-
-
- 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. -
- 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 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: - - - - - - - - Class Name - Value Type - Interpretation - - - - - BooleanGuacamoleProperty - Boolean - The values "true" and "false" are parsed as their corresponding - Boolean values. Any other value results - in a parse error. - - - IntegerGuacamoleProperty - Integer - Numeric strings are parsed as Integer - values. Non-numeric strings will result in a parse error. - - - LongGuacamoleProperty - Long - Numeric strings are parsed as Long values. - Non-numeric strings will result in a parse error. - - - StringGuacamoleProperty - String - The property value is returned as an untouched - String. No parsing is performed, and - parse errors cannot occur. - - - FileGuacamoleProperty - File - 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: - - 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(): - - 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. -
-
- 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: - - 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. - -
-
-
- 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: - - - 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. - - - 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. - - - 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. - - - - 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. - - 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. -
- <classname>SimpleAuthenticationProvider</classname> - 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. -
-
-
- The <classname>UserContext</classname> - 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. -
-
- <classname>Directory</classname> 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. -
-
- 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 - PATH/api/ext/IDENTIFIER, - and the root resource for the UserContext is exposed at - 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. -
-
- 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. - - - -
-
-
- 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. - - 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. - -
-
- 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. - The overall sharing process is as follows: - - - A user, having access to a sharing profile associated with their current - active connection, clicks its option within the share - menu. - - - 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. - - - 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. - - - 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. 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/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 @@ - - - - HTTP header authentication - - 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. - - 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. - -
- 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 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 before - proceeding. - To install the HTTP header authentication extension, you must: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - Copy guacamole-auth-header-1.2.0.jar within - GUACAMOLE_HOME/extensions. - - - Configure Guacamole to use HTTP header authentication, as described - below. - - -
- Configuring Guacamole for HTTP header authentication - - configuring HTTP header authentication - - - HTTP header authentication - configuration - - 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: - - - 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 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/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 @@ - - - - - Event handlers - - 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 @@ - - - Installing Guacamole natively - - installing - - - compiling - Guacamole - - 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 Tomcat. - 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 <package>guacamole-server</package> - - libguac - compiling - - - guacd - compiling - - - VNC support - compiling - - - RDP support - compiling - - - SSH support - compiling - - - telnet support - compiling - - - libguac-client-vnc - compiling - - - libguac-client-rdp - compiling - - - libguac-client-ssh - compiling - - - libguac-client-telnet - compiling - - - libguac-client-kubernetes - compiling - - - guacamole-server - compiling - - 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 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. - - 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, libpng, - and the OSSP UUID library. These libraries are strictly required in all - cases - Guacamole cannot be built without them. - - - - - - - Library name - Features - - - - - Cairo - - Cairo is used by libguac for graphics rendering. Guacamole - cannot function without Cairo installed. - - - - - - - Debian / Ubuntu package - libcairo2-dev - - - Fedora / CentOS / RHEL package - cairo-devel - - - - - - - - libjpeg-turbo - - libjpeg-turbo is used by libguac to provide JPEG support. - Guacamole will not build without this library present: - - - - - - - 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 will work as - well, though it will not be quite as fast: - - - - - - - Debian / Ubuntu package - libjpeg62-dev - - - Fedora / CentOS / RHEL package - libjpeg-devel - - - - - - - - libpng - - libpng is used by libguac to write PNG images, the core image - type used by the Guacamole protocol. Guacamole cannot function - without libpng. - - - - - - - Debian / Ubuntu package - libpng12-dev - - - Fedora / CentOS / RHEL package - libpng-devel - - - - - - - - libtool - - libtool is used during the build process. - libtool creates compiled libraries needed for Guacamole. - - - - - - - Debian / Ubuntu package - libtool-bin - - - Fedora / CentOS / RHEL package - libtool - - - - - - - - libuuid (part of 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. - - - - - - - Debian / Ubuntu package - uuid-dev - - - Fedora / CentOS / RHEL package - libuuid-devel - - - - - If libuuid is unavailable, the OSSP UUID - library may also be used: - - - - - - - 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 (1.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. - - 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. - - - - - - - - Library name - Features - - - - - FFmpeg - - 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. - - - - - - - Debian / Ubuntu package - - libavcodec-dev, - libavformat-dev, - libavutil-dev, - libswscale-dev - - - - Fedora / CentOS / RHEL package - ffmpeg-devel - - - - - - - - FreeRDP - - 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. - - - - - - - Debian / Ubuntu package - freerdp2-dev - - - Fedora / CentOS / RHEL package - freerdp-devel - - - - - - - - Pango - - 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. - - - - - - - Debian / Ubuntu package - libpango1.0-dev - - - Fedora / CentOS / RHEL package - pango-devel - - - - - - - - libssh2 - - libssh2 is required for SSH support. If you do not wish to - build SSH support, this library is not needed. - - - - - - - Debian / Ubuntu package - libssh2-1-dev - - - Fedora / CentOS / RHEL package - libssh2-devel - - - - - - - - libtelnet - - libtelnet is required for telnet support. If you do not wish - to build telnet support, this library is not needed. - - - - - - - Debian / Ubuntu package - libtelnet-dev - - - Fedora / CentOS / RHEL package - libtelnet-devel - - - - - - - - libVNCServer - - libVNCServer provides libvncclient, which is required for VNC - support. If you do not wish to build VNC support, this library - is not needed. - - - - - - - Debian / Ubuntu package - libvncserver-dev - - - Fedora / CentOS / RHEL package - libvncserver-devel - - - - - - - - libwebsockets - - libwebsockets is required for Kubernetes support. If you do - not wish to build Kubernetes support, this library is not - needed. - - - - - - - Debian / Ubuntu package - libwebsockets-dev - - - Fedora / CentOS / RHEL package - libwebsockets-devel - - - - - - - - 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. - - - - - - - Debian / Ubuntu package - libpulse-dev - - - Fedora / CentOS / RHEL package - pulseaudio-libs-devel - - - - - - - - OpenSSL - - 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. - - - - - - - Debian / Ubuntu package - libssl-dev - - - Fedora / CentOS / RHEL package - openssl-devel - - - - - - - - libvorbis - - 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. - - - - - - - Debian / Ubuntu package - libvorbis-dev - - - Fedora / CentOS / RHEL package - libvorbis-devel - - - - - - - - libwebp - - 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. - - - - - - - Debian / Ubuntu package - libwebp-dev - - - Fedora / CentOS / RHEL package - libwebp-devel - - - - - - - - - -
-
- 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: - - $ 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: - - $ 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. -$ - -
-
- 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. - - 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: - - $ 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: - - $ ./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. - -$ - - - guacd - startup script - The 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 - 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. - - 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: - - $ make -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' -$ - - Quite a bit of output will scroll up the screen as all the components are - compiled. -
-
- 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: - - # make install -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' -# 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. -
-
-
- <package>guacamole-client</package> - - guacamole.war - compiling - - - guacamole-client - compiling - - - 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 . - - 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: - - $ 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: - - $ 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: - - $ 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 - - 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: - - # 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: - - # 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: - - # /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 -# - - - 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 . -
- What about WebSocket? - - 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/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 @@ - - - - Database authentication - - MySQL - - - PostgreSQL - - - load balancing - - 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 within . - To use the database authentication extension, you will need: - - - A supported database - currently MariaDB, MySQL, PostgreSQL, or SQL Server. - - - Sufficient permission to create new databases, to create new users, and to grant - those users permissions. - - - Network access to the database from the Guacamole server. - - - - 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 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: - - - mysql/ - - Contains the MySQL/MariaDB authentication extension, - guacamole-auth-jdbc-mysql-1.3.0.jar, along with a - schema/ directory containing MySQL-specific SQL - scripts required to set up the database. The - guacamole-auth-jdbc-mysql-1.3.0.jar file will - ultimately need to be placed within - GUACAMOLE_HOME/extensions, while the MySQL JDBC - driver must be placed within GUACAMOLE_HOME/lib. - The MySQL JDBC driver is not included with the - extension. You must obtain a supported JDBC driver - .jar yourself. The MySQL driver can be downloaded - from MySQL's - website, and is known as "Connector/J". The required - .jar will be within a .tar.gz - archive. - 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. - The mysql-driver 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 mysql-driver property: - - - mysql - - The MySQL JDBC driver, known as Connector/J. - This is the default. - - - - mariadb - - The MariaDB JDBC driver. - - - - - The mysql-server-timezone 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: - - - 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. - Configuration parameters for MySQL-compatible SSL support are as - follows: - - - - - - - Property - Description - - - - - 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. - - - - - - - - - postgresql/ - - Contains the PostgreSQL authentication extension, - guacamole-auth-jdbc-postgresql-1.3.0.jar, along - with a schema/ directory containing PostgreSQL-specific - SQL scripts required to set up the database. The - guacamole-auth-jdbc-postgresql-1.3.0.jar file will - ultimately need to be placed within - GUACAMOLE_HOME/extensions, while the PostgreSQL - JDBC driver must be placed within - GUACAMOLE_HOME/lib. - The PostgreSQL JDBC driver is not included with the - extension. You must obtain the JDBC driver - .jar yourself from PostgreSQL's website. The proper .jar file - depends on the version of Java you have installed. - 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: - - - - - - - Property - Description - - - - - 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 authoritiers. - - - - 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 ignore 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. - - - - - - The PostgreSQL extension also implements some parameters to - configure timeouts at the database and network level. - The parameters are as follows: - - - - - - - Property - Description - - - - - 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. - - - - - - - - - sqlserver/ - - Contains the SQL Server authentication extension, - guacamole-auth-jdbc-sqlserver-1.3.0.jar, along with - a schema/ directory contains SQL Server-specific - scripts requires to set up the database. The JAR extension file will need to - be placed within the GUACAMOLE_HOME/extensions folder, - while the SQL Server JDBC driver must be placed within the - GUACAMOLE_HOME/lib directory. - The SQL Server JDBC driver is not included with the extension. You - must obtain the JDBC driver .jar 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 .jar is in the correct - directory. Microsoft's JDBC driver can be downloaded from Microsoft's - SQL Connection Libraries page. - In addition to the various parameters mentioned below, the SQL Server driver implements - two parameters to control SQL Server-specific configuration items: - sqlserver-driver and sqlserver-instance. - The sqlserver-instance 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. - The sqlserver-driver 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 sqlserver-driver property: - - - microsoft2005 - - The current Microsoft driver, supporting SQL Server 2005 and later. - - - - microsoft - - The legacy SQL Server support. - - - - jtds - - The open source JTDS driver. - - - - datadirect - - The Progress Sybase driver. - - - - - - - - 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. -
-
- 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. -
- MySQL - - $ ls schema/ -001-create-schema.sql 002-create-admin-user.sql upgrade -$ cat schema/*.sql | mysql -u root -p guacamole_db -Enter password: password -$ - -
-
- PostgreSQL - - $ 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 -$ - -
-
- SQL Server - - $ /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -d guacamole_db -i schema/001-create-schema.sql -Password: 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: password - -(1 rows affected) - -(3 rows affected) - -(5 rows affected) - - -
-
-
- 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 - 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 - 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). - - 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 -$ - - -
-
- 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. -
- MySQL - - $ mysql -u root -p -Enter password: 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> 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 -$ - -
-
- PostgreSQL - - $ 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 -$ - -
-
- SQL Server - - $ /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -Password: password -1> CREATE DATABASE guacamole_db; -2> GO -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 - -
-
-
- 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: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - 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. - - - 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. - - - Configure Guacamole to use database authentication, as described below. - - - - 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. - -
- 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. - To use a MySQL database, you will need to specify the following: - - # MySQL properties -mysql-hostname: localhost -mysql-port: 3306 -mysql-database: guacamole_db -mysql-username: guacamole_user -mysql-password: some_password - - - For PostgreSQL, the properties are similar, but with different prefixes: - - # PostgreSQL properties -postgresql-hostname: localhost -postgresql-port: 5432 -postgresql-database: guacamole_db -postgresql-username: guacamole_user -postgresql-password: some_password - - - The SQL Server properties follow the same format: - - # SQL Server properties -sqlserver-hostname: localhost -sqlserver-port: 1433 -sqlserver-database: guacamole_db -sqlserver-username: guacamole_user -sqlserver-password: some_password -sqlserver-driver: microsoft2005 - - - 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: - - - - - - - - - MySQL/MariaDB Property - PostgreSQL Property - SQL Server Property - Description - - - - - mysql-hostname - postgresql-hostname - sqlserver-hostname - - The hostname or IP address of the server hosting your - database. - - - - mysql-port - postgresql-port - sqlserver-port - - 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. - - - - mysql-database - postgresql-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. - - - - mysql-username - postgresql-username - 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. - - - - mysql-password - postgresql-password - 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. - - - - - - 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. -
- 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, 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. - - # 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 - -# 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 - -# 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: - - - Requiring users to change their password after a certain amount of - time has elapsed since the last password change (maximum password - age). - - - 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: - - # MySQL -mysql-user-password-min-age: 7 -mysql-user-password-max-age: 90 - -# PostgreSQL -postgresql-user-password-min-age: 7 -postgresql-user-password-max-age: 90 - -# SQL Server -sqlserver-user-password-min-age: 7 -sqlserver-user-password-max-age: 90 - - - 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. - - # MySQL -mysql-user-password-history-size: 6 - -# PostgreSQL -postgresql-user-password-history-size: 6 - -# SQL Server -sqlserver-user-password-history-size: 6 - -
-
-
- 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: - - # 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 - - 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: - - # 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 - - 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: - - # MySQL -mysql-absolute-max-connections: 0 - -# PostgreSQL -postgresql-absolute-max-connections: 0 - -# SQL Server -sqlserver-absolute-max-connections: 0 - -
-
-
- 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, 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: - - # MySQL -mysql-user-required: true - -# PostgreSQL -postgresql-user-required: true - -# 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. -
-
- 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. - - # MySQL -mysql-auto-create-accounts: true - -# PostgreSQL -postgresql-auto-create-accounts: true - -# 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. - - - 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. -
-
-
- Logging in - - default user - - - guacadmin - - 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 . -
-
- Modifying data manually - - schema - - 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. -
- Entities - - guacamole_entity - - 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 or the user group - entry in guacamole_user_group. - - - - 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. - - - -
-
- Users - - guacamole_user - - Every user has a corresponding entry in the guacamole_user - and guacamole_entity 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 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(), 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. - - - - - 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: - - -- 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). -
- Password history - - guacamole_user_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). - - - -
-
- Login history - - guacamole_user_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. - - - -
-
-
- User groups - - guacamole_user_group - - Similar to users, every user group - has a corresponding entry in the guacamole_user_group and - guacamole_entity tables. Each user group has - a corresponding unique name specified via - guacamole_entity. - If deleting a user group, the corresponding entity 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. - - - - - guacamole_user_group_member - - 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. - - - -
-
- Connections and parameters - - guacamole_connection - - - guacamole_connection_parameter - - 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 with the - mysql-default-max-connections or - postgresql-default-max-connections 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 with the - mysql-default-max-connections or - postgresql-default-max-connections 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: - - -- 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'); - -
- Usage history - - guacamole_connection_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 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. - - - -
-
-
- Sharing profiles and parameters - - guacamole_sharing_profile - - - guacamole_sharing_profile_parameter - - 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. - - - -
-
- Connection groups - - guacamole_connection_group - - 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 with the - mysql-default-max-connections or - postgresql-default-max-connections 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 with the - mysql-default-max-connections or - postgresql-default-max-connections 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: - - -- Create connection group -INSERT INTO guacamole_connection_group (connection_group_name, type) - VALUES ('test', 'ORGANIZATIONAL'); - -
-
- 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. -
- lSystem permissions - - guacamole_system_permission - - 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. - - - -
-
- User permissions - - guacamole_user_permission - - 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. - - - -
-
- User group permissions - - guacamole_user_group_permission - - 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. - - - -
-
- Connection permissions - - guacamole_connection_permission - - 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. - - - -
-
- Sharing profile permissions - - guacamole_sharing_profile_permission - - 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. - - - -
-
- Connection group permissions - - guacamole_connection_group_permission - - 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/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 @@ - - - - LDAP authentication - - LDAP - - 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: - - - An LDAP directory as storage for all authentication data, such as OpenLDAP. - - - 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. - - 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 before proceeding. - -
- 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: - - - Your users can use their existing usernames and passwords to log into - Guacamole. - - - You can manage Guacamole connections using the same tool that you already use - to manage your LDAP directory, such as Apache Directory - Studio. - - - Existing security restrictions can limit visibility/accessibility of Guacamole - connections. - - - Access to connections can easily be granted and revoked, as each connection is - represented by a group. - - - - 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 and later in this chapter in . - -
-
- 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. - - - -
-
- 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 . - 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). - - 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 ldapadd - utility with the provided guacConfigGroup.ldif file: - - # 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 ldapsearch: - - # 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 - -# - -
-
-
- Associating LDAP with a database - If you install both the LDAP authentication as well as support for a database - (following the instructions in ), 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. - 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 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: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - Copy guacamole-auth-ldap-1.3.0.jar within - GUACAMOLE_HOME/extensions. - - - Configure Guacamole to use LDAP authentication, as described below. - - - - 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. - -
- Configuring Guacamole for LDAP - - configuring LDAP - - - LDAP - configuration - - 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 - 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 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". For example: - - Example LDAP attribute / parameter token conversions - - - - - - 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 in . -
-
- - 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 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. - - - - 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. - - - 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. -
-
-
- The LDAP schema - - 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 ldapadd - utility: - - $ 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, which make many of the tasks given above much - easier. -
-
-
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 @@ - - - libguac - - API - C - - - 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. -
- 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. -
-
- Client plugins - Client plugins are libraries which follow specific conventions such that they can be - loaded dynamically by guacd. All client plugins must: - - - Follow a naming convention, where the name of the library is - libguac-client-PROTOCOL. - This is necessary for guacd to locate the library for a requested - protocol. - - - 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. - - - 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. - - -
- 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: - - - 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. - - - 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. - - - A handler for users leaving the connection - (leave_handler), if any cleanup, updates, etc. are - required. - - - 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. -
-
- 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: - - 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: - - int leave_handler(guac_user* user) { - /* Free user-specific data and clean up */ -} - -... - -/* Within guac_client_init */ -client->leave_handler = leave_handler; - -
-
- 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: - - int free_handler(guac_client* client) { - /* Disconnect, free client-specific data, etc. */ -} - -... - -/* Within guac_client_init */ -client->free_handler = free_handler; - -
-
-
- 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(). - - 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 to the main display of the connected client - somehow, this is the layer you want to use as the operand of your - drawing instruction. -
-
- 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(). - - 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), audio (via the "audio" instruction), and even the images which make up typical drawing - operations (via the "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 - and . -
-
- 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 - 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: - - 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: - - 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. -
-
- 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. -
- 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. - - int key_handler(guac_user* user, int keysym, int pressed) { - /* Do something */ -} - -... - -/* Within the "join" handler of guac_client */ -user->key_handler = key_handler; - -
-
- 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. - - 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. - - - -
-
- 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. - - 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" and "end" instructions received along the stream - can be handled. A similar handler is provided for received files: - - 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 and appropriate error code, informing the user's Guacamole - client that the stream is unsupported. -
-
-
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 @@ - - - - OpenID Connect Authentication - - OpenID Connect Authentication - - OpenID Connect is a widely-adopted - open standard for implementing single sign-on (SSO). Not to be confused with - OAuth, 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" 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, as it only provides - user authentication. -
- 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 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 before - proceeding. - To install the OpenID Connect authentication extension, you must: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - Copy guacamole-auth-openid-1.3.0.jar within - GUACAMOLE_HOME/extensions. - - - Configure Guacamole to use OpenID Connect authentication, as described - below. - - -
- Configuring Guacamole for single sign-on with OpenID Connect - - configuring OpenID Connect authentication - - - OpenID Connect authentication - configuration - - 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, this value can be retrieved from - the "authorization_endpoint" property of the JSON - file hosted at - 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 or - JWTs) shall be validated. - This value should be provided to you by the identity provider. For - identity providers that implement OpenID Connect Discovery, this value can be retrieved from - the "jwks_uri" property of the JSON file hosted at - 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, this value can be retrieved from - the "issuer" property of the JSON file hosted at - 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 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/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 @@ - - - The Guacamole protocol - - 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. -
- 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. -
-
- 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 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: - - - - - - - Version - Value - Description - - - - - 1.0.0 - 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). - - - 1.1.0 - VERSION_1_1_0 - 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. - - - - - - 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: - - - handshake - instructions - - - - - - - Instruction name - Description - - - - - 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 - , 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. -
- 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. - -
-
-
- Drawing -
- 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. - - - -
-
- 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 . - 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. -
-
- 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. -
-
- 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. -
-
- 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. -
-
-
- 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. -
-
- 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. -
-
- 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/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 @@ - - - - RADIUS Authentication - - 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. -
- 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 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 - to the Maven command line during the build, and should result in the output below: - - $ 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 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: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - Copy guacamole-auth-radius-1.3.0.jar into - GUACAMOLE_HOME/extensions. - - - Configure Guacamole to use RADIUS authentication, as described - below. - - -
-
- Configuring Guacamole for RADIUS authentication - - configuring RADIUS authentication - - - RADIUS authentication - configuration - - 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 - 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 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/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 @@ - - - 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 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: - - - WebSocket will not work over AJP, forcing Guacamole to fallback to HTTP, - possibly resulting in reduced performance. - - - 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: - - <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. -
- 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 and is configured in the - conf/server.xml file, in the <Host> section: - - - <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: - - - - - - - - Parameter name - Description - - - - - 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 - the Apache web server - passes it through by default. -
-
-
- Nginx - Nginx can be used as a reverse proxy, and supports WebSocket out-of-the-box since version 1.3. Both - Apache and Nginx require some additional configuration for proxying of WebSocket to work - properly. -
- 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 block, declaring the backend hosting Guacamole - and explicitly specifying the "Connection" and "Upgrade" headers mentioned - earlier: - - location /guacamole/ { - 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; -} - - 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 - , 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. - - 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 the path - If you wish to serve Guacamole through Nginx under a path other than - /guacamole/, 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. - Regardless of the location specified for the proxy, cookies set by Guacamole will - be set using its own absolute path within the backend (/guacamole/). If - this path differs from that used by Nginx, the path in the cookie needs to be - modified using proxy_cookie_path: - - 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; - proxy_cookie_path /guacamole/ /new-path/; - access_log off; -} - -
-
- 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: - - location /guacamole/ { - 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; - client_max_body_size 1g; - access_log off; -} - -
-
-
- Apache and <package>mod_proxy</package> - Apache supports reverse proxy configurations through mod_proxy. Apache 2.4.5 and later also support - proxying of WebSocket through a sub-module called mod_proxy_wstunnel. 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 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: - - <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. - - Do not forget the - 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 is not specified, - Guacamole may not work. - -
-
- 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: - - <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. - - 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 the path - If you wish to serve Guacamole through Apache under a path other than - /guacamole/, the configuration required for Apache will be slightly - different than the examples above due to cookies. - 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. - Cookies are set using the absolute path of the web application - (/guacamole/). If this path differs from that used by Apache, the - path in the cookie needs to be modified using the - ProxyPassReverseCookiePath directive: - - <Location /new-path/> - Order allow,deny - Allow from all - ProxyPass http://HOSTNAME:8080/guacamole/ flushpackets=on - ProxyPassReverse http://HOSTNAME:8080/guacamole/ - ProxyPassReverseCookiePath /guacamole/ /new-path/ -</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> - - This directive is not needed for the WebSocket section, as it is not applicable. - Cookies are only used by Guacamole within the HTTP tunnel. -
-
- 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: - - 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/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 @@ - - - - SAML Authentication - - 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. -
- 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 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 before - proceeding. - To install the SAML authentication extension, you must: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - Copy guacamole-auth-saml-1.3.0.jar within - GUACAMOLE_HOME/extensions. - - - Configure Guacamole to use SAML authentication, as described - below. - - -
- Configuring Guacamole for SAML Authentication - - configuring SAML authentication - - - SAML authentication - configuration - - 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 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 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/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 @@ - - - - TOTP two-factor authentication - - TOTP - - 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 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. - - 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 before proceeding. - -
- 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. - 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 . -
-
- 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. -
- 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. -
-
-
- 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 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: - - - Create the GUACAMOLE_HOME/extensions directory, if it - does not already exist. - - - Copy guacamole-auth-totp-1.3.0.jar within - GUACAMOLE_HOME/extensions. - - - Configure Guacamole to use TOTP authentication, as described below. - - - - 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. - -
- Configuring Guacamole for TOTP - - configuring TOTP - - - TOTP - configuration - - With the exception of the storage and - permission requirements described above, 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 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. - - - 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/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 @@ - - - Troubleshooting - - troubleshooting - - - errors - -
- 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 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. -
- No graphics appear - - Connecting, waiting for first update... - - - proxies - - 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 - - Unicode - - - UTF-8 - - - URIEncoding - - 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 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. -
-
-
- syslog - - 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 - - errors - guacd - - - 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 - 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 <replaceable>input</replaceable> - 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() - <replaceable>parent</replaceable> - 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: - <replaceable>HOSTNAME</replaceable> - 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 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. - 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 "<replaceable>OPCODE</replaceable>" - 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 <replaceable>parameter</replaceable> - 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 "<replaceable>name</replaceable>": 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). -
- <filename>user-mapping.xml</filename> 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. -
-
-
- <filename>guacamole.properties</filename> errors - If a property is malformed or a required property is missing, - an error describing the problem will be logged. -
- Property <replaceable>PROPERTY</replaceable> 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. -
-
- Specified authentication provider class is not a - AuthenticationProvider - The auth-provider property allows you to - specify a custom authentication provider class which will - handle all authentication, but these classes must implement - the AuthenticationProvider interface. - If the class specified does not, this error will be logged. - Check that your authentication provider class implements - AuthenticationProvider (if you - implemented it yourself), and verify that you are specifying - the correct class. - 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 lib-directory - parameter in guacamole.properties. -
-
- Resource /guacamole.properties not found - Guacamole requires that the - guacamole.properties file is in the - classpath of your servlet container. If it is not, this - error will be logged. Check that - guacamole.properties is in the - proper location, and then restart your servlet - container. -
-
- Missing "basic-user-mapping" parameter required for basic - login - If you are using the authentication provider included with - Guacamole, it requires the basic-user-mapping - property to be set. If this property is missing, you will - see this error. Add the missing property to - guacamole.properties, restart your - servlet container, and try again. -
-
-
- 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. -
-
-
- 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/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 @@ - - - - - Using Guacamole - - interacting - 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. - - - - - - - - The Guacamole home screen. The user menu and several recently-used - connections are visible, along with one active connection. - - - - - 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 . - - - - 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. - - - - - - - - Guacamole client interface, with the Guacamole menu open. - - - - - 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. -
- 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 - 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 - 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 - - -
-
-
- Copying/pasting text - - clipboard - 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. -
-
- 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. - - - 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. - -
-
- 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. -
-
- Transferring files - - file transfer - - 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. -
- 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. - - - - - - The file browser within the Guacamole menu. - - - 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. - - - - - - In-progress and completed file transfers. - - - When you are done browsing the filesystem and transferring files, click "Back" to - return to the Guacamole menu. -
-
- 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. - - - - - - The Guacamole drive within a Windows RDP session. - - - 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. - - - - - - The Guacamole drive's "Download" folder. - - -
-
- <command>guacctl</command> / <command>guacget</command> - - guacctl - - guacget - - SSH - guacctl - - SSH - guacget - In addition to traditional drag-and-drop and the file browser, - Guacamole's SSH support can be used with the guacctl utility. The - guacctl utility is a simple shell script included with Guacamole which allows you to use and configure file - transfer directly from the command line within the SSH session: - - $ 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 - guacctl called guacget. When run as - guacget, the utility behaves as if the - option were supplied and initiates a download for - each file specified on the command line. -
-
-
- On-screen keyboard - Certain key combinations are impossible to press within a web application like - Guacamole because they are reserved by the operating system ( - Ctrl - Alt - Del - or - 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 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 the display - - zoom - 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. -
-
- 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. -
- Mouse emulation - - mouse - 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 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 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. - - - - - - - -
-
-
- 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. - - input method editors - 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. -
-
-
- 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. - - - - - - - - Guacamole preferences screen. - - - - -
- 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 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/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 @@ - - - - Writing your own Guacamole application - - custom application - - - application - development - - 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. -
- 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: - - 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. - - - 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 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. -
- <filename>pom.xml</filename> - 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: - - <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> - -
-
- <filename>WEB-INF/web.xml</filename> - 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 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> - -
-
- <filename>index.html</filename> - 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: - - <!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: - - $ 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/. -
-
-
- 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. -
- Updating <filename>pom.xml</filename> - 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 1.6, thus we must add a section to the - pom.xml which describes the source and target Java - versions: - - ... - - <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> - - ... - - 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: - - ... - - <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: - - ... - - <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. -
-
- 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: - - 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: - - ... - - <!-- 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. -
-
- 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: - - ... - <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: - - ... - - <!-- 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> - - ... - -
-
-
- 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/src/conf.py b/src/conf.py new file mode 100644 index 0000000..1cb221e --- /dev/null +++ b/src/conf.py @@ -0,0 +1,52 @@ +# -*- 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. + +# +# Project, version, and author information +# + +project = u'Apache Guacamole' +version = u'1.3.0' + +copyright = u'2021, The Apache Software Foundation' +author = u'The Apache Software Foundation' + +# +# Global options +# + +extensions = [ + 'sphinx.ext.ifconfig', + 'sphinx.ext.extlinks' +] + +# Allow shorthand notation for JIRA issue links +extlinks = { + 'jira': ( 'https://issues.apache.org/jira/browse/%s', '') +} + +# Do not highlight source unless a Pygments lexer name is explicitly provided +highlight_language = 'none' + +# +# HTML output options +# + +html_theme = 'sphinx_rtd_theme' +html_title = u'Apache Guacamole Manual v%s' % version + diff --git a/src/configuring.rst b/src/configuring.rst new file mode 100644 index 0000000..f3d72b1 --- /dev/null +++ b/src/configuring.rst @@ -0,0 +1,4540 @@ +.. _configuring-guacamole: + +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: + + .. container:: informalexample + + :: + + 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. + + .. container:: informalexample + + :: + + 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: + + .. container:: informalexample + + :: + + 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. + +:: + + # 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 `__ 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``: + +.. container:: informalexample + + :: + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + +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 `__ 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: + +:: + + + + + + vnc + localhost + 5900 + VNCPASS + + + + + + + + vnc + localhost + 5901 + VNCPASS + + + + + vnc + otherhost + 5900 + VNCPASS + + + + + + +Each user is specified with a corresponding ```` tag. This +tag contains all authorized connections for that user, each denoted with +a ```` tag. Each ```` tag contains a +corresponding protocol and set of protocol-specific parameters, +specified with the ```` and ```` tags respectively. + +.. _user-setup: + +Adding users +^^^^^^^^^^^^ + +When using ``BasicFileAuthenticationProvider``, username/password pairs +are specified with ```` tags, which each have a ``username`` +and ``password`` attribute. Each ```` tag authorizes a +specific username/password pair to access all connections within the +tag: + +:: + + + ... + + +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: + +:: + + + ... + + +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 ```` tag, you can either +list a single protocol and set of parameters (specified with a +```` tag and any number of ```` 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 +```` tags, each of which can be named and contains a +```` tag and any number of ```` 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. + +.. _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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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 + . For example, if your VNC | +| | server is serving display number 1 (sometimes written | +| | as ``:1``), your port number here would be 5901. | ++--------------+-------------------------------------------------------+ +| ` | The number of times to retry connecting before giving | +| `autoretry`` | 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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``c | The color depth to request, in bits-per-pixel. This | +| olor-depth`` | 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. | ++--------------+-------------------------------------------------------+ +| ``swa | If the colors of your display appear wrong (blues | +| p-red-blue`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | A space-delimited list of VNC encodings to use. The | +| `encodings`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | Whether this connection should be read-only. If set | +| `read-only`` | 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. | ++--------------+-------------------------------------------------------+ +| ``forc | Whether this connection should only use lossless | +| e-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-recording: + +Session recording +^^^^^^^^^^^^^^^^^ + +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 ``guacenc`` utility provided with +guacamole-server. + +For example, to produce a video called ".m4v" from the recording +"", you would run: + +.. container:: informalexample + + :: + + $ guacenc /path/to/recording/NAME + +The ``guacenc`` utility has additional options for overriding default +behavior, including tweaking the output format, which are documented in +detail within the manpage: + +.. container:: informalexample + + :: + + $ 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 ``guaclog`` utility. The usage of ``guaclog`` is +analogous to ``guacenc``, and results in the creation of a new text file +containing the interpreted events: + +.. container:: informalexample + + :: + + $ 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 + to avoid overwriting an existing recording. If even appending a + numeric suffix does not help, the session will simply not be + recorded. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``reco | The directory in which screen recording files should | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | If set to "true", the directory specified by the | +| `create-reco | ``recording-path`` parameter will automatically be | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ``reco | The filename to use for any created recordings. *This | +| rding-name`` | 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. | ++--------------+-------------------------------------------------------+ +| ``re | If set to "true", graphical output and other data | +| cording-excl | normally streamed from server to client will be | +| ude-output`` | 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. | ++--------------+-------------------------------------------------------+ +| ``r | If set to "true", user mouse events will be excluded | +| ecording-exc | from the recording, producing a recording which lacks | +| lude-mouse`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | If set to "true", user key events will be included in | +| recording-in | the recording. The recording can subsequently be | +| clude-keys`` | passed through the ``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. | ++--------------+-------------------------------------------------------+ + +.. _vnc-sftp: + +File transfer (via SFTP) +^^^^^^^^^^^^^^^^^^^^^^^^ + +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 `Using Guacamole <#using-guacamole>`__. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``e | Whether file transfer should be enabled. If set to | +| nable-sftp`` | "true", the user will be allowed to upload or | +| | download files from the specified server using SFTP. | +| | If omitted, SFTP will be disabled. | ++--------------+-------------------------------------------------------+ +| ``sft | The hostname or IP address of the server hosting | +| p-hostname`` | SFTP. This parameter is optional. If omitted, the | +| | hostname of the VNC server specified with the | +| | ``hostname`` parameter will be used. | ++--------------+-------------------------------------------------------+ +| ` | The port the SSH server providing SFTP is listening | +| `sftp-port`` | on, usually 22. This parameter is optional. If | +| | omitted, the standard port of 22 will be used. | ++--------------+-------------------------------------------------------+ +| ``sft | The known hosts entry for the SFTP server. This | +| p-host-key`` | 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 should be that of a | +| | single entry from an OpenSSH ``known_hosts`` file. | +| | | +| | For more information, please see `SSH Host | +| | Verification <#ssh-host-verification>`__. | ++--------------+-------------------------------------------------------+ +| ``sft | The username to authenticate as when connecting to | +| p-username`` | the specified SSH server for SFTP. This parameter is | +| | required. | ++--------------+-------------------------------------------------------+ +| ``sft | The password to use when authenticating with the | +| p-password`` | specified SSH server for SFTP. | ++--------------+-------------------------------------------------------+ +| ``sftp-p | The entire contents of the private key to use for | +| rivate-key`` | 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 ``ssh-keygen`` | +| | utility. | ++--------------+-------------------------------------------------------+ +| ``sftp- | The passphrase to use to decrypt the private key for | +| passphrase`` | use in public key authentication. This parameter is | +| | not needed if the private key does not require a | +| | passphrase. | ++--------------+-------------------------------------------------------+ +| ``sftp | The directory to upload files to if they are simply | +| -directory`` | 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 | The directory to expose to connected users via | +| -directory`` | Guacamole's `file browser <#file-browser>`__. If | +| | omitted, the root directory will be used by default. | ++--------------+-------------------------------------------------------+ +| ``sftp | The interval in seconds at which to send keepalive | +| -server-aliv | packets to the SSH server for the SFTP connection. | +| e-interval`` | This parameter is optional. If omitted, the default | +| | of 0 will be used, disabling sending keepalive | +| | packets. The minimum value is 2. | ++--------------+-------------------------------------------------------+ +| ` | If set to true downloads from the remote system to | +| `sftp-disabl | the client (browser) will be disabled. The default is | +| e-download`` | false, which means that downloads will be enabled. | +| | | +| | If sftp is not enabled, this parameter will be | +| | ignored. | ++--------------+-------------------------------------------------------+ +| ``sftp-disa | If set to true uploads from the client (browser) to | +| ble-upload`` | 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. | ++--------------+-------------------------------------------------------+ + +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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ` | The destination host to request when connecting to a | +| `dest-host`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | The destination port to request when connecting to a | +| `dest-port`` | 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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``rever | Whether reverse connection should be used. If set to | +| se-connect`` | "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. | ++--------------+-------------------------------------------------------+ +| ``list | If reverse connection is in use, the maximum amount | +| en-timeout`` | 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``: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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 ``netstat``: + +.. container:: informalexample + + :: + + $ 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: + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``en | If set to "true", audio support will be enabled, and | +| able-audio`` | a second connection for PulseAudio will be made in | +| | addition to the VNC connection. By default, audio | +| | support within VNC is disabled. | ++--------------+-------------------------------------------------------+ +| ``audio- | The name of the PulseAudio server to connect to. This | +| servername`` | 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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``clipboar | The encoding to assume for the VNC clipboard. This | +| d-encoding`` | parameter is optionl. 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. | ++--------------+-------------------------------------------------------+ + +.. _vnc-disable-clipboard: + +Disabling clipboard access +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Guacamole provides bidirectional access to the clipboard by default for +VNC connections. This behavior can be overridden on a per-connection +basis with the ``disable-copy`` and ``disable-paste`` parameters. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``di | If set to "true", text copied within the VNC session | +| sable-copy`` | 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. | ++--------------+-------------------------------------------------------+ +| ``dis | If set to "true", text copied at the browser side of | +| able-paste`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _vnc-wake-on-lan: + +Wake-on-LAN Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^ + +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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``wol-s | If set to "true", Guacamole will attempt to send the | +| end-packet`` | 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. | ++--------------+-------------------------------------------------------+ +| ``wo | This parameter configures the MAC address that | +| l-mac-addr`` | 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-broa | This parameter configures the IPv4 broadcast address | +| dcast-addr`` | 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. | ++--------------+-------------------------------------------------------+ +| ``wo | This parameter configures the UDP port that will be | +| l-udp-port`` | 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 | By default after the WoL packet is sent Guacamole | +| -wait-time`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _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 ```` section for that user within your +``user-mapping.xml``, and add a section like the following within it: + +:: + + + vnc + localhost + 5901 + + +If added exactly as above, a new connection named "" will +be available to the user associated with the ```` section +containing it. The connection will use VNC to connect to 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 ```` 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. + +.. _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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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 support <#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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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 `__" | +| | 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`` | +| | 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. | ++--------------+-------------------------------------------------------+ +| ``i | If set to "true", the certificate returned by the | +| gnore-cert`` | 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). | ++--------------+-------------------------------------------------------+ +| ``di | If set to "true", authentication will be disabled. | +| sable-auth`` | 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 `__. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``c | When connecting to the RDP server, Guacamole will | +| lient-name`` | 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. | ++--------------+-------------------------------------------------------+ +| ``initi | The full path to the program to run immediately upon | +| al-program`` | connecting. This parameter is optional. | ++--------------+-------------------------------------------------------+ +| ``ser | The server-side keyboard layout. This is the layout | +| ver-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: | +| | | +| | ``en-us-qwerty`` | +| | English (US) keyboard | +| | | +| | ``en-gb-qwerty`` | +| | English (UK) keyboard | +| | | +| | ``de-ch-qwertz`` | +| | Swiss German keyboard (qwertz) | +| | | +| | ``de-de-qwertz`` | +| | German keyboard (qwertz) | +| | | +| | ``fr-be-azerty`` | +| | Belgian French keyboard (azerty) | +| | | +| | ``fr-fr-azerty`` | +| | French keyboard (azerty) | +| | | +| | ``fr-ch-qwertz`` | +| | Swiss French keyboard (qwertz) | +| | | +| | ``hu-hu-qwertz`` | +| | Hungarian keyboard (qwertz) | +| | | +| | ``it-it-qwerty`` | +| | Italian keyboard | +| | | +| | ``ja-jp-qwerty`` | +| | Japanese keyboard | +| | | +| | ``pt-br-qwerty`` | +| | Portuguese Brazilian keyboard | +| | | +| | ``es-es-qwerty`` | +| | Spanish keyboard | +| | | +| | ``es-latam-qwerty`` | +| | Latin American keyboard | +| | | +| | ``sv-se-qwerty`` | +| | Swedish keyboard | +| | | +| | ``tr-tr-qwerty`` | +| | Turkish-Q keyboard | +| | | +| | ``failsafe`` | +| | Unknown keyboard - this option sends only Unicode | +| | events and should work for any keyboard, though | +| | not necessarily all RDP servers or applications. | +| | | +| | If your server's keyboard layout is not yet | +| | supported, this option should work in the | +| | meantime. | ++--------------+-------------------------------------------------------+ +| ``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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``c | The color depth to request, in bits-per-pixel. This | +| olor-depth`` | 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. | ++--------------+-------------------------------------------------------+ +| ``res | The method to use to update the RDP server when the | +| ize-method`` | 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. | ++--------------+-------------------------------------------------------+ +| ``forc | Whether this connection should only use lossless | +| e-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-recording: + +Session recording +^^^^^^^^^^^^^^^^^ + +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 ``guacenc`` utility provided with +guacamole-server. + +For example, to produce a video called ".m4v" from the recording +"", you would run: + +.. container:: informalexample + + :: + + $ guacenc /path/to/recording/NAME + +The ``guacenc`` utility has additional options for overriding default +behavior, including tweaking the output format, which are documented in +detail within the manpage: + +.. container:: informalexample + + :: + + $ 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 ``guaclog`` utility. The usage of ``guaclog`` is +analogous to ``guacenc``, and results in the creation of a new text file +containing the interpreted events: + +.. container:: informalexample + + :: + + $ 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 + to avoid overwriting an existing recording. If even appending a + numeric suffix does not help, the session will simply not be + recorded. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``reco | The directory in which screen recording files should | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | If set to "true", the directory specified by the | +| `create-reco | ``recording-path`` parameter will automatically be | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ``reco | The filename to use for any created recordings. *This | +| rding-name`` | 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. | ++--------------+-------------------------------------------------------+ +| ``re | If set to "true", graphical output and other data | +| cording-excl | normally streamed from server to client will be | +| ude-output`` | 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. | ++--------------+-------------------------------------------------------+ +| ``r | If set to "true", user mouse events will be excluded | +| ecording-exc | from the recording, producing a recording which lacks | +| lude-mouse`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | If set to "true", user key events will be included in | +| recording-in | the recording. The recording can subsequently be | +| clude-keys`` | passed through the ``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. | ++--------------+-------------------------------------------------------+ + +.. _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 SSH connection, users will be able to upload and +download files as described in `Using Guacamole <#using-guacamole>`__. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``dis | Audio is enabled by default in both the client and in | +| able-audio`` | 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-a | If set to "true", audio input support (microphone) | +| udio-input`` | will be enabled, leveraging the standard | +| | "AUDIO_INPUT" channel of RDP. By default, audio input | +| | support within RDP is disabled. | ++--------------+-------------------------------------------------------+ +| ``enabl | Printing is disabled by default, but with printing | +| e-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. | ++--------------+-------------------------------------------------------+ +| ``pr | The name of the redirected printer device that is | +| inter-name`` | 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. | ++--------------+-------------------------------------------------------+ +| ``en | File transfer is disabled by default, but with file | +| able-drive`` | 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. | ++--------------+-------------------------------------------------------+ +| ``disabl | If set to true downloads from the remote server to | +| e-download`` | 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. | +| | | +| | If file transfer is not enabled, this parameter is | +| | ignored. | ++--------------+-------------------------------------------------------+ +| ``disa | If set to true, uploads from the client (browser) to | +| ble-upload`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | The name of the filesystem used when passed through | +| drive-name`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | The directory on the Guacamole server in which | +| drive-path`` | 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- | If set to "true", and file transfer is enabled, the | +| drive-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ``con | If set to "true", audio will be explicitly enabled in | +| sole-audio`` | 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". | ++--------------+-------------------------------------------------------+ +| ``stati | A comma-separated list of static channel names to | +| c-channels`` | 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" `__ +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: + +.. container:: informalexample + + :: + + 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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``precon | The numeric ID of the RDP source. This is a | +| nection-id`` | 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.* | ++--------------+-------------------------------------------------------+ +| ``preconne | An arbitrary string which identifies the RDP source - | +| ction-blob`` | 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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``gatewa | The hostname of the remote desktop gateway that | +| y-hostname`` | should be used as an intermediary for the remote | +| | desktop connection. *If omitted, a gateway will not | +| | be used.* | ++--------------+-------------------------------------------------------+ +| ``ga | The port of the remote desktop gateway that should be | +| teway-port`` | used as an intermediary for the remote desktop | +| | connection. By default, this will be "443". | ++--------------+-------------------------------------------------------+ +| ``gatewa | The username of the user authenticating with the | +| y-username`` | remote desktop gateway, if a gateway is being used. | +| | This is not necessarily the same as the user actually | +| | using the remote desktop connection. | ++--------------+-------------------------------------------------------+ +| ``gatewa | The password to provide when authenticating with the | +| y-password`` | remote desktop gateway, if a gateway is being used. | ++--------------+-------------------------------------------------------+ +| ``gate | The domain of the user authenticating with the remote | +| way-domain`` | 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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``load-ba | The load balancing information or cookie which should | +| lance-info`` | be provided to the connection broker. *If no | +| | connection broker is being used, this should be left | +| | blank.* | ++--------------+-------------------------------------------------------+ + +RDP + SFTP +^^^^^^^^^^ + +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 `Using Guacamole <#using-guacamole>`__. + +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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``e | Whether file transfer should be enabled. If set to | +| nable-sftp`` | "true", the user will be allowed to upload or | +| | download files from the specified server using SFTP. | +| | If omitted, SFTP will be disabled. | ++--------------+-------------------------------------------------------+ +| ``sft | The hostname or IP address of the server hosting | +| p-hostname`` | SFTP. This parameter is optional. If omitted, the | +| | hostname of the RDP server specified with the | +| | ``hostname`` parameter will be used. | ++--------------+-------------------------------------------------------+ +| ` | The port the SSH server providing SFTP is listening | +| `sftp-port`` | on, usually 22. This parameter is optional. If | +| | omitted, the standard port of 22 will be used. | ++--------------+-------------------------------------------------------+ +| ``sft | The known hosts entry for the SFTP server. This | +| p-host-key`` | 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 <#ssh-host-verification>`__. | ++--------------+-------------------------------------------------------+ +| ``sft | The username to authenticate as when connecting to | +| p-username`` | 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 | +| | ``username`` parameter will be use. | ++--------------+-------------------------------------------------------+ +| ``sft | The password to use when authenticating with the | +| p-password`` | specified SSH server for SFTP. | ++--------------+-------------------------------------------------------+ +| ``sftp-p | The entire contents of the private key to use for | +| rivate-key`` | 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 ``ssh-keygen`` | +| | utility. | ++--------------+-------------------------------------------------------+ +| ``sftp- | The passphrase to use to decrypt the private key for | +| passphrase`` | use in public key authentication. This parameter is | +| | not needed if the private key does not require a | +| | passphrase. | ++--------------+-------------------------------------------------------+ +| ``sftp | The directory to upload files to if they are simply | +| -directory`` | 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 | The directory to expose to connected users via | +| -directory`` | Guacamole's `file browser <#file-browser>`__. If | +| | omitted, the root directory will be used by default. | ++--------------+-------------------------------------------------------+ +| ``sftp | The interval in seconds at which to send keepalive | +| -server-aliv | packets to the SSH server for the SFTP connection. | +| e-interval`` | This parameter is optional. If omitted, the default | +| | of 0 will be used, disabling sending keepalive | +| | packets. The minimum value is 2. | ++--------------+-------------------------------------------------------+ +| ` | If set to true downloads from the remote system to | +| `sftp-disabl | the client (browser) will be disabled. The default is | +| e-download`` | false, which means that downloads will be enabled. | +| | | +| | If sftp is not enabled, this parameter will be | +| | ignored. | ++--------------+-------------------------------------------------------+ +| ``sftp-disa | If set to true uploads from the client (browser) to | +| ble-upload`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _rdp-disable-clipboard: + +Disabling clipboard access +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Guacamole provides bidirectional access to the clipboard by default for +RDP connections. This behavior can be overridden on a per-connection +basis with the ``disable-copy`` and ``disable-paste`` parameters. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``di | If set to "true", text copied within the RDP session | +| sable-copy`` | 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. | ++--------------+-------------------------------------------------------+ +| ``dis | If set to "true", text copied at the browser side of | +| able-paste`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _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. + ++------------------+---------------------------------------------------+ +| Parameter name | Description | ++==================+===================================================+ +| ``en | If set to "true", enables rendering of the | +| able-wallpaper`` | desktop wallpaper. By default, wallpaper will be | +| | disabled, such that unnecessary bandwidth need | +| | not be spent redrawing the desktop. | ++------------------+---------------------------------------------------+ +| `` | If set to "true", enables use of theming of | +| enable-theming`` | windows and controls. By default, theming within | +| | RDP sessions is disabled. | ++------------------+---------------------------------------------------+ +| ``enable- | If set to "true", text will be rendered with | +| font-smoothing`` | 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-fu | If set to "true", the contents of windows will be | +| ll-window-drag`` | displayed as windows are moved. By default, the | +| | RDP server will only draw the window border while | +| | windows are being dragged. | ++------------------+---------------------------------------------------+ +| ``enable-deskt | If set to "true", graphical effects such as | +| op-composition`` | transparent windows and shadows will be allowed. | +| | By default, such effects, if available, are | +| | disabled. | ++------------------+---------------------------------------------------+ +| ``enable-m | If set to "true", menu open and close animations | +| enu-animations`` | will be allowed. Menu animations are disabled by | +| | default. | ++------------------+---------------------------------------------------+ +| ``disable- | In certain situations, particularly with RDP | +| bitmap-caching`` | 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-off | RDP normally maintains caches of regions of the | +| screen-caching`` | 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. | ++------------------+---------------------------------------------------+ +| ``disable | In addition to screen regions, RDP maintains | +| -glyph-caching`` | 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. | ++------------------+---------------------------------------------------+ + +.. _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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| `` | Specifies the RemoteApp to start on the remote | +| remote-app`` | 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". | ++--------------+-------------------------------------------------------+ +| ``remo | The working directory, if any, for the remote | +| te-app-dir`` | application. This parameter has no effect if | +| | RemoteApp is not in use. | ++--------------+-------------------------------------------------------+ +| ``remot | The command-line arguments, if any, for the remote | +| e-app-args`` | application. This parameter has no effect if | +| | RemoteApp is not in use. | ++--------------+-------------------------------------------------------+ + +.. _rdp-wake-on-lan: + +Wake-on-LAN Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^ + +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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``wol-s | If set to "true", Guacamole will attempt to send the | +| end-packet`` | 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. | ++--------------+-------------------------------------------------------+ +| ``wo | This parameter configures the MAC address that | +| l-mac-addr`` | 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-broa | This parameter configures the IPv4 broadcast address | +| dcast-addr`` | 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. | ++--------------+-------------------------------------------------------+ +| ``wo | This parameter configures the UDP port that will be | +| l-udp-port`` | 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 | By default after the WoL packet is sent Guacamole | +| -wait-time`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _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 ```` section for that user within your +``user-mapping.xml``, and add a section like the following within it: + +:: + + + rdp + localhost + 3389 + + +If added exactly as above, a new connection named "" will +be available to the user associated with the ```` section +containing it. The connection will use RDP to connect to 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 +```` 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. + +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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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 <#ssh-host-verification>`__. | ++--------------+-------------------------------------------------------+ +| ` | By default the SSH client does not send keepalive | +| `server-aliv | requests to the server. This parameter allows you to | +| e-interval`` | 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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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. | ++--------------+-------------------------------------------------------+ +| ``p | The entire contents of the private key to use for | +| rivate-key`` | 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 ``ssh-keygen`` | +| | utility. | ++--------------+-------------------------------------------------------+ +| `` | The passphrase to use to decrypt the private key for | +| passphrase`` | 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-display-settings: + +Display settings +^^^^^^^^^^^^^^^^ + +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, *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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``co | The color scheme to use for the terminal emulator | +| lor-scheme`` | 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: | +| | | +| | .. container:: informalexample | +| | | +| | :: | +| | | +| | 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. | +| | | +| | ``color`` | +| | Set the color at index ```` on the Xterm | +| | 256-color palette. For example, ``color9`` refers | +| | to the red color. | +| | | +| | Possible color values are: | +| | | +| | ``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. | +| | | +| | ``color`` | +| | Use the color currently assigned to index ```` | +| | 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. | ++--------------+-------------------------------------------------------+ +| ` | The name of the font to use. This parameter is | +| `font-name`` | optional. If not specified, the default of | +| | "monospace" will be used instead. | ++--------------+-------------------------------------------------------+ +| ` | The size of the font to use, in points. This | +| `font-size`` | parameter is optional. If not specified, the default | +| | of 12 will be used instead. | ++--------------+-------------------------------------------------------+ +| `` | The maximum number of rows to allow within the | +| scrollback`` | terminal scrollback buffer. This parameter is | +| | optional. If not specified, the scrollback buffer | +| | will be limited to a maximum of 1000 rows. | ++--------------+-------------------------------------------------------+ + +.. _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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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-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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ` | This parameter controls the ASCII code that the | +| `backspace`` | 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. | ++--------------+-------------------------------------------------------+ +| ``ter | This parameter sets the terminal emulator type string | +| minal-type`` | that is passed to the SSH server. This parameter is | +| | optional. If not specified, "``linux``" is used as | +| | the terminal emulator type by default. | ++--------------+-------------------------------------------------------+ + +.. _ssh-stdin-pipe: + +Providing input directly from JavaScript +'''''''''''''''''''''''''''''''''''''''' + +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 +```createPipeStream()`` <../guacamole-common-js/Guacamole.Client.html#createPipeStream>`__ +function of +```Guacamole.Client`` <../guacamole-common-js/Guacamole.Client.html>`__: + +.. container:: informalexample + + :: + + var outputStream = client.createPipeStream('text/plain', 'STDIN'); + +The resulting +```Guacamole.OutputStream`` <../guacamole-common-js/Guacamole.OutputStream.html>`__ +can then be used to stream data directly to the input of the SSH +session, as if typed by the user: + +.. container:: informalexample + + :: + + // 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(); + +.. _ssh-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``: ``NAME``, +which contains the raw text data, and ``NAME.timing``, which contains +timing information, where is the value provided for the +``typescript-name`` parameter. + +This format is compatible with the format used by the standard UNIX +``script`` command, and can be replayed using ``scriptreplay`` (if +installed). For example, to replay a typescript called "", you +would run: + +.. container:: informalexample + + :: + + $ 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 + to avoid overwriting an existing recording. If even appending a + numeric suffix does not help, the session will simply not be + recorded. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``types | The directory in which typescript files should be | +| cript-path`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | If set to "true", the directory specified by the | +| create-types | ``typescript-path`` parameter will automatically be | +| cript-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ``types | The base filename to use when determining the names | +| cript-name`` | 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``: ``NAME``, which contains the raw | +| | text data, and ``NAME.timing``, which contains timing | +| | information, where 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. | ++--------------+-------------------------------------------------------+ + +.. _ssh-recording: + +Graphical session recording +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 +``guacenc`` utility provided with guacamole-server. + +For example, to produce a video called ".m4v" from the recording +"", you would run: + +.. container:: informalexample + + :: + + $ guacenc /path/to/recording/NAME + +The ``guacenc`` utility has additional options for overriding default +behavior, including tweaking the output format, which are documented in +detail within the manpage: + +.. container:: informalexample + + :: + + $ 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 ``guaclog`` utility. The usage of ``guaclog`` is +analogous to ``guacenc``, and results in the creation of a new text file +containing the interpreted events: + +.. container:: informalexample + + :: + + $ 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 + to avoid overwriting an existing recording. If even appending a + numeric suffix does not help, the session will simply not be + recorded. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``reco | The directory in which screen recording files should | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | If set to "true", the directory specified by the | +| `create-reco | ``recording-path`` parameter will automatically be | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ``reco | The filename to use for any created recordings. *This | +| rding-name`` | 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. | ++--------------+-------------------------------------------------------+ +| ``re | If set to "true", graphical output and other data | +| cording-excl | normally streamed from server to client will be | +| ude-output`` | 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. | ++--------------+-------------------------------------------------------+ +| ``r | If set to "true", user mouse events will be excluded | +| ecording-exc | from the recording, producing a recording which lacks | +| lude-mouse`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | If set to "true", user key events will be included in | +| recording-in | the recording. The recording can subsequently be | +| clude-keys`` | passed through the ``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. | ++--------------+-------------------------------------------------------+ + +.. _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 <#using-guacamole>`__. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``e | Whether file transfer should be enabled. If set to | +| nable-sftp`` | "true", the user will be allowed to upload or | +| | download files from the SSH server using SFTP. | +| | Guacamole includes the ``guacctl`` utility which | +| | controls file downloads and uploads when run on the | +| | SSH server by the user over the SSH connection. | ++--------------+-------------------------------------------------------+ +| ``sftp-root | The directory to expose to connected users via | +| -directory`` | Guacamole's `file browser <#file-browser>`__. If | +| | omitted, the root directory will be used by default. | ++--------------+-------------------------------------------------------+ +| ` | If set to true downloads from the remote system to | +| `sftp-disabl | the client (browser) will be disabled. The default is | +| e-download`` | false, which means that downloads will be enabled. | +| | | +| | If sftp is not enabled, this parameter will be | +| | ignored. | ++--------------+-------------------------------------------------------+ +| ``sftp-disa | If set to true uploads from the client (browser) to | +| ble-upload`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _ssh-disable-clipboard: + +Disabling clipboard access +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 ``disable-copy`` and ``disable-paste`` +parameters. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``di | If set to "true", text copied within the SSH session | +| sable-copy`` | 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. | ++--------------+-------------------------------------------------------+ +| ``dis | If set to "true", text copied at the browser side of | +| able-paste`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _ssh-wake-on-lan: + +Wake-on-LAN Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^ + +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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``wol-s | If set to "true", Guacamole will attempt to send the | +| end-packet`` | 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. | ++--------------+-------------------------------------------------------+ +| ``wo | This parameter configures the MAC address that | +| l-mac-addr`` | 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-broa | This parameter configures the IPv4 broadcast address | +| dcast-addr`` | 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. | ++--------------+-------------------------------------------------------+ +| ``wo | This parameter configures the UDP port that will be | +| l-udp-port`` | 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 | By default after the WoL packet is sent Guacamole | +| -wait-time`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _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 ```` section for that user within your +``user-mapping.xml``, and add a section like the following within it: + +:: + + + ssh + localhost + 22 + + +If added exactly as above, a new connection named "" will +be available to the user associated with the ```` section +containing it. The connection will use SSH to connect to 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 +```` 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. + +.. _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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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``). + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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. | ++--------------+-------------------------------------------------------+ +| ``user | The regular expression to use when waiting for the | +| name-regex`` | 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``). | ++--------------+-------------------------------------------------------+ +| ``pass | The regular expression to use when waiting for the | +| word-regex`` | 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-suc | The regular expression to use when detecting that the | +| cess-regex`` | 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-fai | The regular expression to use when detecting that the | +| lure-regex`` | 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``). | ++--------------+-------------------------------------------------------+ + +.. _telnet-display-settings: + +Display settings +^^^^^^^^^^^^^^^^ + +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, *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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``co | The color scheme to use for the terminal emulator | +| lor-scheme`` | 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: | +| | | +| | .. container:: informalexample | +| | | +| | :: | +| | | +| | 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. | +| | | +| | ``color`` | +| | Set the color at index ```` on the Xterm | +| | 256-color palette. For example, ``color9`` refers | +| | to the red color. | +| | | +| | Possible color values are: | +| | | +| | ``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. | +| | | +| | ``color`` | +| | Use the color currently assigned to index ```` | +| | 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. | ++--------------+-------------------------------------------------------+ +| ` | The name of the font to use. This parameter is | +| `font-name`` | optional. If not specified, the default of | +| | "monospace" will be used instead. | ++--------------+-------------------------------------------------------+ +| ` | The size of the font to use, in points. This | +| `font-size`` | parameter is optional. If not specified, the default | +| | of 12 will be used instead. | ++--------------+-------------------------------------------------------+ +| `` | The maximum number of rows to allow within the | +| scrollback`` | terminal scrollback buffer. This parameter is | +| | optional. If not specified, the scrollback buffer | +| | will be limited to a maximum of 1000 rows. | ++--------------+-------------------------------------------------------+ + +.. _telnet-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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ` | This parameter controls the ASCII code that the | +| `backspace`` | 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. | ++--------------+-------------------------------------------------------+ +| ``ter | This parameter sets the terminal emulator type string | +| minal-type`` | that is passed to the telnet server. This parameter | +| | is optional. If not specified, "``linux``" is used as | +| | the terminal emulator type by default. | ++--------------+-------------------------------------------------------+ + +.. _telnet-stdin-pipe: + +Providing input directly from JavaScript +'''''''''''''''''''''''''''''''''''''''' + +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 +```createPipeStream()`` <../guacamole-common-js/Guacamole.Client.html#createPipeStream>`__ +function of +```Guacamole.Client`` <../guacamole-common-js/Guacamole.Client.html>`__: + +.. container:: informalexample + + :: + + var outputStream = client.createPipeStream('text/plain', 'STDIN'); + +The resulting +```Guacamole.OutputStream`` <../guacamole-common-js/Guacamole.OutputStream.html>`__ +can then be used to stream data directly to the input of the telnet +session, as if typed by the user: + +.. container:: informalexample + + :: + + // 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(); + +.. _telnet-typescripts: + +Text session recording (typescripts) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 ``typescript-path``: ``NAME``, +which contains the raw text data, and ``NAME.timing``, which contains +timing information, where is the value provided for the +``typescript-name`` parameter. + +This format is compatible with the format used by the standard UNIX +``script`` command, and can be replayed using ``scriptreplay`` (if +installed). For example, to replay a typescript called "", you +would run: + +.. container:: informalexample + + :: + + $ 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 + to avoid overwriting an existing recording. If even appending a + numeric suffix does not help, the session will simply not be + recorded. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``types | The directory in which typescript files should be | +| cript-path`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | If set to "true", the directory specified by the | +| create-types | ``typescript-path`` parameter will automatically be | +| cript-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ``types | The base filename to use when determining the names | +| cript-name`` | 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``: ``NAME``, which contains the raw | +| | text data, and ``NAME.timing``, which contains timing | +| | information, where 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. | ++--------------+-------------------------------------------------------+ + +.. _telnet-recording: + +Graphical session recording +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 +``guacenc`` utility provided with guacamole-server. + +For example, to produce a video called ".m4v" from the recording +"", you would run: + +.. container:: informalexample + + :: + + $ guacenc /path/to/recording/NAME + +The ``guacenc`` utility has additional options for overriding default +behavior, including tweaking the output format, which are documented in +detail within the manpage: + +.. container:: informalexample + + :: + + $ 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 ``guaclog`` utility. The usage of ``guaclog`` is +analogous to ``guacenc``, and results in the creation of a new text file +containing the interpreted events: + +.. container:: informalexample + + :: + + $ 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 + to avoid overwriting an existing recording. If even appending a + numeric suffix does not help, the session will simply not be + recorded. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``reco | The directory in which screen recording files should | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | If set to "true", the directory specified by the | +| `create-reco | ``recording-path`` parameter will automatically be | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ``reco | The filename to use for any created recordings. *This | +| rding-name`` | 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. | ++--------------+-------------------------------------------------------+ +| ``re | If set to "true", graphical output and other data | +| cording-excl | normally streamed from server to client will be | +| ude-output`` | 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. | ++--------------+-------------------------------------------------------+ +| ``r | If set to "true", user mouse events will be excluded | +| ecording-exc | from the recording, producing a recording which lacks | +| lude-mouse`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | If set to "true", user key events will be included in | +| recording-in | the recording. The recording can subsequently be | +| clude-keys`` | passed through the ``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. | ++--------------+-------------------------------------------------------+ + +.. _telnet-disable-clipboard: + +Disabling clipboard access +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 ``disable-copy`` and ``disable-paste`` +parameters. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``di | If set to "true", text copied within the telnet | +| sable-copy`` | 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. | ++--------------+-------------------------------------------------------+ +| ``dis | If set to "true", text copied at the browser side of | +| able-paste`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _telnet-wake-on-lan: + +Wake-on-LAN Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^ + +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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``wol-s | If set to "true", Guacamole will attempt to send the | +| end-packet`` | 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. | ++--------------+-------------------------------------------------------+ +| ``wo | This parameter configures the MAC address that | +| l-mac-addr`` | 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-broa | This parameter configures the IPv4 broadcast address | +| dcast-addr`` | 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. | ++--------------+-------------------------------------------------------+ +| ``wo | This parameter configures the UDP port that will be | +| l-udp-port`` | 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 | By default after the WoL packet is sent Guacamole | +| -wait-time`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _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 ```` section for that user within your +``user-mapping.xml``, and add a section like the following within it: + +:: + + + telnet + localhost + 23 + + +If added exactly as above, a new connection named "" will +be available to the user associated with the ```` section +containing it. The connection will use telnet to connect to +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. + +.. _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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| 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. | ++--------------+-------------------------------------------------------+ +| ` | The name of the Kubernetes namespace of the pod | +| `namespace`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | The name of the container to attach to. *This | +| `container`` | parameter is optional.* If omitted, the first | +| | container in the pod will be used. | ++--------------+-------------------------------------------------------+ +| ``ex | The command to run within the container, with input | +| ec-command`` | 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 ``kubectl | +| | exec``. | +| | When omitted, the behavior is analogous to running | +| | ``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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``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. | ++--------------+-------------------------------------------------------+ +| ``c | The certificate to use if performing SSL/TLS client | +| lient-cert`` | authentication to authenticate with the Kubernetes | +| | server, in PEM format. *This parameter is optional.* | +| | If omitted, SSL client authentication will not be | +| | performed. | ++--------------+-------------------------------------------------------+ +| `` | The key to use if performing SSL/TLS client | +| client-key`` | 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. | ++--------------+-------------------------------------------------------+ +| ``i | If set to "true", the validity of the SSL/TLS | +| gnore-cert`` | 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. | ++--------------+-------------------------------------------------------+ + +.. _kubernetes-display-settings: + +Display settings +^^^^^^^^^^^^^^^^ + +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, *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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``co | The color scheme to use for the terminal emulator | +| lor-scheme`` | 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: | +| | | +| | .. container:: informalexample | +| | | +| | :: | +| | | +| | 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. | +| | | +| | ``color`` | +| | Set the color at index ```` on the Xterm | +| | 256-color palette. For example, ``color9`` refers | +| | to the red color. | +| | | +| | Possible color values are: | +| | | +| | ``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. | +| | | +| | ``color`` | +| | Use the color currently assigned to index ```` | +| | 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. | ++--------------+-------------------------------------------------------+ +| ` | The name of the font to use. This parameter is | +| `font-name`` | optional. If not specified, the default of | +| | "monospace" will be used instead. | ++--------------+-------------------------------------------------------+ +| ` | The size of the font to use, in points. This | +| `font-size`` | parameter is optional. If not specified, the default | +| | of 12 will be used instead. | ++--------------+-------------------------------------------------------+ +| ` | Whether this connection should be read-only. If set | +| `read-only`` | to "true", no input will be accepted on the | +| | connection at all. Users will only see the console of | +| | the Kubernetes container. *This parameter is | +| | optional.* If omitted, the connection will not be | +| | read-only. | ++--------------+-------------------------------------------------------+ +| `` | The maximum number of rows to allow within the | +| scrollback`` | terminal scrollback buffer. This parameter is | +| | optional. If not specified, the scrollback buffer | +| | will be limited to a maximum of 1000 rows. | ++--------------+-------------------------------------------------------+ + +.. _kubernetes-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. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ` | This parameter controls the ASCII code that the | +| `backspace`` | 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. | ++--------------+-------------------------------------------------------+ +| ``ter | This parameter sets the terminal emulator type string | +| minal-type`` | that is passed to the Kubernetes server. This | +| | parameter is optional. If not specified, "``linux``" | +| | is used as the terminal emulator type by default. | ++--------------+-------------------------------------------------------+ + +.. _kubernetes-typescripts: + +Text session recording (typescripts) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 ``typescript-path``: ``NAME``, +which contains the raw text data, and ``NAME.timing``, which contains +timing information, where is the value provided for the +``typescript-name`` parameter. + +This format is compatible with the format used by the standard UNIX +``script`` command, and can be replayed using ``scriptreplay`` (if +installed). For example, to replay a typescript called "", you +would run: + +.. container:: informalexample + + :: + + $ 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 + to avoid overwriting an existing recording. If even appending a + numeric suffix does not help, the session will simply not be + recorded. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``types | The directory in which typescript files should be | +| cript-path`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | If set to "true", the directory specified by the | +| create-types | ``typescript-path`` parameter will automatically be | +| cript-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ``types | The base filename to use when determining the names | +| cript-name`` | 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``: ``NAME``, which contains the raw | +| | text data, and ``NAME.timing``, which contains timing | +| | information, where 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. | ++--------------+-------------------------------------------------------+ + +.. _kubernetes-recording: + +Graphical session recording +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 ``guacenc`` utility provided with guacamole-server. + +For example, to produce a video called ".m4v" from the recording +"", you would run: + +.. container:: informalexample + + :: + + $ guacenc /path/to/recording/NAME + +The ``guacenc`` utility has additional options for overriding default +behavior, including tweaking the output format, which are documented in +detail within the manpage: + +.. container:: informalexample + + :: + + $ 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 ``guaclog`` utility. The usage of ``guaclog`` is +analogous to ``guacenc``, and results in the creation of a new text file +containing the interpreted events: + +.. container:: informalexample + + :: + + $ 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 + to avoid overwriting an existing recording. If even appending a + numeric suffix does not help, the session will simply not be + recorded. + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``reco | The directory in which screen recording files should | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | If set to "true", the directory specified by the | +| `create-reco | ``recording-path`` parameter will automatically be | +| rding-path`` | 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. | ++--------------+-------------------------------------------------------+ +| ``reco | The filename to use for any created recordings. *This | +| rding-name`` | 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. | ++--------------+-------------------------------------------------------+ +| ``re | If set to "true", graphical output and other data | +| cording-excl | normally streamed from server to client will be | +| ude-output`` | 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. | ++--------------+-------------------------------------------------------+ +| ``r | If set to "true", user mouse events will be excluded | +| ecording-exc | from the recording, producing a recording which lacks | +| lude-mouse`` | 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. | ++--------------+-------------------------------------------------------+ +| `` | If set to "true", user key events will be included in | +| recording-in | the recording. The recording can subsequently be | +| clude-keys`` | passed through the ``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. | ++--------------+-------------------------------------------------------+ + +.. _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 ```` section for that user +within your ``user-mapping.xml``, and add a section like the following +within it: + +:: + + + kubernetes + localhost + mypod + + +If added exactly as above, a new connection named "" will +be available to the user associated with the ```` section +containing it. The connection will connect to the Kubernetes server +running on and attach to the first container of the pod +. + +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 ``${TOKEN_NAME}`` or +``${TOKEN_NAME:MODIFIER}``, where is some descriptive name +for the value the token represents, and the optional 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}". + +``${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 ``${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``: + +.. container:: informalexample + + :: + + 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 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. + +.. _guacd.conf: + +Configuring guacd +----------------- + +guacd is configured with a configuration file called ``guacd.conf``, by +default located in ``/etc/guacamole``. This file follows a simple, +INI-like format: + +.. container:: informalexample + + :: + + # + # 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: + +.. container:: informalexample + + :: + + [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: + +.. container:: informalexample + + :: + + # 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. + +.. table:: guacd.conf parameters + + +-------+--------------+----------------------------------------------+ + | Se | Name | Description | + | ction | | | + +=======+==============+==============================================+ + | ``dae | ``pid_file`` | The name of the file in which the PID of the | + | mon`` | | 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. | + +-------+--------------+----------------------------------------------+ + | ``dae | ` | The maximum level at which guacd will log | + | mon`` | `log_level`` | 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``. | + +-------+--------------+----------------------------------------------+ + | ``ser | ` | The host that guacd should bind to when | + | ver`` | `bind_host`` | listening for connections. If unspecified, | + | | | guacd will bind to localhost, and only | + | | | connections from within the server hosting | + | | | guacd will succeed. | + +-------+--------------+----------------------------------------------+ + | ``ser | ` | The port that guacd should bind to when | + | ver`` | `bind_port`` | listening for connections. If unspecified, | + | | | port 4822 will be used. | + +-------+--------------+----------------------------------------------+ + | `` | ``server_c | The filename of the certificate to use for | + | ssl`` | ertificate`` | 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. | + +-------+--------------+----------------------------------------------+ + | `` | `` | The filename of the private key to use for | + | ssl`` | server_key`` | 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. | + +-------+--------------+----------------------------------------------+ + +You can also affect the configuration of guacd with command-line +options. If given, these options take precendence over the system-wide +configuration file: + +``-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``. + +``-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``. + +``-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``. + +``-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``. + +``-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: + +``-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``. + +``-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``. + diff --git a/src/custom-auth.rst b/src/custom-auth.rst new file mode 100644 index 0000000..33f50d2 --- /dev/null +++ b/src/custom-auth.rst @@ -0,0 +1,514 @@ +.. _custom-auth: + +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. + +:: + + + + 4.0.0 + org.apache.guacamole + guacamole-auth-tutorial + jar + 1.3.0 + guacamole-auth-tutorial + + + UTF-8 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.6 + 1.6 + + + + + + + + + + + org.apache.guacamole + guacamole-ext + 1.3.0 + provided + + + + + + +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``. + +:: + + 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 + 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 <#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``. + +:: + + { + + "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 `Installing the +extension <#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: + +.. container:: informalexample + + :: + + $ 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. + +:: + + 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. + +:: + + @Override + public Map + 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(); + + } + +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. + +:: + + @Override + public Map + 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 configs = + new HashMap(); + + // 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 +`Building the extension <#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 <#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: + +.. container:: informalexample + + :: + + Extension "Tutorial Authentication Extension" loaded. + diff --git a/src/docker.rst b/src/docker.rst new file mode 100644 index 0000000..664adc5 --- /dev/null +++ b/src/docker.rst @@ -0,0 +1,909 @@ +.. _guacamole-docker: + +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. + +.. container:: informalexample + + :: + + $ 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). + +.. container:: informalexample + + :: + + $ 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. + +.. container:: informalexample + + :: + + $ 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 +http://:8080/guacamole/, where 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 <#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: + +.. container:: informalexample + + :: + + $ 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: + + +-------------+--------------------------------------------------------+ + | Variable | Description | + +=============+========================================================+ + | ``GUACD | The hostname of the guacd instance to use to establish | + | _HOSTNAME`` | remote desktop connections. *This is required if you | + | | are not using Docker to provide guacd.* | + +-------------+--------------------------------------------------------+ + | ``G | The port that Guacamole should use when connecting to | + | UACD_PORT`` | 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: + + :: + + $ 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 `Database authentication <#jdbc-auth>`__: + +.. container:: informalexample + + :: + + $ 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: + +- Create a database for Guacamole within MySQL, such as . + +- Create a user for Guacamole within MySQL with access to this + database, such as ``guacamole_user``. + +- Run the script on the newly-created database. + +The process for doing this via the ``mysql`` utility included with MySQL +is documented in `Database authentication <#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: + +.. container:: informalexample + + :: + + $ 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: + ++-------------+--------------------------------------------------------+ +| Variable | Description | ++=============+========================================================+ +| ``MYSQL | The hostname of the database to use for Guacamole | +| _HOSTNAME`` | authentication. *This is required if you are not using | +| | Docker to provide your MySQL database.* | ++-------------+--------------------------------------------------------+ +| ``M | The port that Guacamole should use when connecting to | +| YSQL_PORT`` | 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: + +.. container:: informalexample + + :: + + $ 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 `Connecting Guacamole to <#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: + ++-------------+--------------------------------------------------------+ +| Variable | Description | ++=============+========================================================+ +| ``MYSQL | The name of the database to use for Guacamole | +| _DATABASE`` | authentication. | ++-------------+--------------------------------------------------------+ +| ``M | The user that Guacamole will use to connect to MySQL. | +| YSQL_USER`` | | ++-------------+--------------------------------------------------------+ +| ``MYSQL | The password that Guacamole will provide when | +| _PASSWORD`` | 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: + ++--------------------------------+-------------------------------------+ +| Variable | Description | ++================================+=====================================+ +| ``MY | The absolute maximum number of | +| SQL_ABSOLUTE_MAX_CONNECTIONS`` | 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").* | ++--------------------------------+-------------------------------------+ +| ``M | The maximum number of concurrent | +| YSQL_DEFAULT_MAX_CONNECTIONS`` | 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_D | The maximum number of concurrent | +| EFAULT_MAX_GROUP_CONNECTIONS`` | 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_DEFA | The maximum number of concurrent | +| ULT_MAX_CONNECTIONS_PER_USER`` | 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_MA | The maximum number of concurrent | +| X_GROUP_CONNECTIONS_PER_USER`` | 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 `Database +authentication <#jdbc-auth>`__: + +.. container:: informalexample + + :: + + $ 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: + +- Create a database for Guacamole within PostgreSQL, such as + . + +- Run the script on the newly-created database. + +- 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 ``psql`` and ``createdb`` utilities +included with PostgreSQL is documented in `Database +authentication <#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: + +.. container:: informalexample + + :: + + $ 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: + ++-------------+--------------------------------------------------------+ +| Variable | Description | ++=============+========================================================+ +| ``POSTGRES | The hostname of the database to use for Guacamole | +| _HOSTNAME`` | authentication. *This is required if you are not using | +| | Docker to provide your PostgreSQL database.* | ++-------------+--------------------------------------------------------+ +| ``POST | The port that Guacamole should use when connecting to | +| GRES_PORT`` | 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: + +.. container:: informalexample + + :: + + $ 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 `Connecting Guacamole to <#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: + ++-------------+--------------------------------------------------------+ +| Variable | Description | ++=============+========================================================+ +| ``POSTGRES | The name of the database to use for Guacamole | +| _DATABASE`` | authentication. | ++-------------+--------------------------------------------------------+ +| ``POST | The user that Guacamole will use to connect to | +| GRES_USER`` | PostgreSQL. | ++-------------+--------------------------------------------------------+ +| ``POSTGRES | The password that Guacamole will provide when | +| _PASSWORD`` | 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: + ++--------------------------------+-------------------------------------+ +| Variable | Description | ++================================+=====================================+ +| ``POSTG | The absolute maximum number of | +| RES_ABSOLUTE_MAX_CONNECTIONS`` | 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").* | ++--------------------------------+-------------------------------------+ +| ``POST | The maximum number of concurrent | +| GRES_DEFAULT_MAX_CONNECTIONS`` | 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_D | The maximum number of concurrent | +| EFAULT_MAX_GROUP_CONNECTIONS`` | 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_DEFA | The maximum number of concurrent | +| ULT_MAX_CONNECTIONS_PER_USER`` | 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_MA | The maximum number of concurrent | +| X_GROUP_CONNECTIONS_PER_USER`` | 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. | ++--------------------------------+-------------------------------------+ +| ``P | Whether or not accounts that do not | +| OSTGRES_AUTO_CREATE_ACCOUNTS`` | 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: + ++--------------------------------+-------------------------------------+ +| Variable | Description | ++================================+=====================================+ +| ``POSTGR | The number of seconds the driver | +| ES_DEFAULT_STATEMENT_TIMEOUT`` | 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 | +| | ``PO | +| | STGRES_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: + ++---------------+-------------------------------------------------------+ +| Variable | Description | ++===============+=======================================================+ +| ``LD | The hostname or IP address of your LDAP server. | +| AP_HOSTNAME`` | | ++---------------+-------------------------------------------------------+ +| ``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_ENCRYP | The encryption mechanism that Guacamole should use | +| TION_METHOD`` | 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: + +.. container:: informalexample + + :: + + $ 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 `Connecting Guacamole to +<#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: + ++-------------+--------------------------------------------------------+ +| Variable | Description | ++=============+========================================================+ +| ``LDAP_USE | The base of the DN for all Guacamole users. All | +| R_BASE_DN`` | 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: + ++---------------------+------------------------------------------------+ +| Variable | Description | ++=====================+================================================+ +| ``L | The base of the DN for all groups that may be | +| DAP_GROUP_BASE_DN`` | 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.* | ++---------------------+------------------------------------------------+ +| ``LD | The DN (Distinguished Name) of the user to | +| AP_SEARCH_BIND_DN`` | 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_SEA | The password to provide to the LDAP server | +| RCH_BIND_PASSWORD`` | 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_U | The attribute or attributes which contain the | +| SERNAME_ATTRIBUTE`` | 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``*. | ++---------------------+------------------------------------------------+ +| ``LD | The base of the DN for all Guacamole | +| AP_CONFIG_BASE_DN`` | 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 authentication <#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: + ++---------------------+------------------------------------------------+ +| Variable | Description | ++=====================+================================================+ +| ``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. | ++---------------------+------------------------------------------------+ +| ` | Optional environment variable that, if set, | +| `HTTP_AUTH_HEADER`` | 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: + ++-------------+--------------------------------------------------------+ +| Variable | Description | ++=============+========================================================+ +| ``GUACA | The absolute path to the directory within the Docker | +| MOLE_HOME`` | 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: + +.. container:: informalexample + + :: + + $ 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 +http://:8080/guacamole/, where is the hostname or address of +the machine hosting Docker, and you *should* 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: + +.. container:: informalexample + + :: + + $ docker logs some-guacamole + diff --git a/src/duo-auth.rst b/src/duo-auth.rst new file mode 100644 index 0000000..d63c8cb --- /dev/null +++ b/src/duo-auth.rst @@ -0,0 +1,201 @@ +.. _duo-auth: + +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 <#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: + +.. image:: images/duo-auth-factor-1.png + +Only after authentication has succeeded with one of those methods will +Guacamole reach out to Duo to obtain additional verification of user +identity: + +.. image:: images/duo-auth-factor-2.png + +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: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- Copy ``guacamole-auth-duo-1.3.0.jar`` within + ``GUACAMOLE_HOME/extensions``. + +- 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: + +.. image:: images/duo-add-guacamole.png + +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: + +.. image:: images/duo-rename-guacamole.png + +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``: + +.. image:: images/duo-copy-details.png + +.. _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-.duosecurity.com `__", where "" + 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``: + +.. container:: informalexample + + :: + + $ 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``: + +.. container:: informalexample + + :: + + $ 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.rst b/src/event-listeners.rst new file mode 100644 index 0000000..ba255e0 --- /dev/null +++ b/src/event-listeners.rst @@ -0,0 +1,391 @@ +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. + +:: + + + + 4.0.0 + org.apache.guacamole + guacamole-listener-tutorial + jar + 1.3.0 + guacamole-listener-tutorial + + + UTF-8 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.6 + 1.6 + + + + + + + + + + + org.apache.guacamole + guacamole-ext + 1.3.0 + provided + + + + + + org.slf4j + slf4j-api + 1.7.7 + provided + + + + + + +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. + +:: + + 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 <#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``. + +:: + + { + + "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. + +.. container:: informalexample + + :: + + $ 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 `Installing the +extension <#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. + +:: + + 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 +`Building the extension <#custom-listener-building>`__ and installed as +described below in `Installing the +extension <#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 "blacklist" 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. + +:: + + 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()); + } + } + + } + +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. + +.. _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 <#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: + +.. container:: informalexample + + :: + + Extension "Tutorial Listener Extension" loaded. + diff --git a/src/faq.rst b/src/faq.rst new file mode 100644 index 0000000..1e4d8ea --- /dev/null +++ b/src/faq.rst @@ -0,0 +1,157 @@ +FAQ +=== + +**Q:** Where does the name "Guacamole" come from? + +**A:** The name was chosen arbitrarily from a random utterance in a +conversation with a member of the project. + +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. + +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". + +The name had a nice ring, we weren't embarrassed to use it, and it +stuck. + +**Q:** What does "clientless" mean? + +**A:** 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. + +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. + +**Q:** Does Guacamole use WebSocket? + +**A:** 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. + +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. + +**Q:** 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? + +**A:** You need to enable automatic flushing of the proxy's buffer as it +receives packets. + +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. + +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. + +In the case of mod_proxy, this option is ``flushpackets=on``. + +**Q:** I connect to the internet through a web proxy, and cannot connect +to Guacamole. I cannot reconfigure the proxy. How do I solve this? + +**A:** You need to enable automatic flushing of your proxy's buffer to +avoid disrupting the stream used by Guacamole. + +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. + +**Q:** 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? + +**A:** 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. + +**Q:** Can I pay for custom Guacamole work, or for help integrating +Guacamole into my product, if the open source nature and licenses are +preserved? + +**A:** Yes. We love to be paid to work on Guacamole, especially if that +work remains open source. + +**Q:** How can I contribute to the project? + +**A:** 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. + +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. + +**Q:** How can I become an official member of the project? + +**A:** The short answer is: "by being asked." + +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. + +All that said, you do not need to be a member of the project to help +out. Feel free to contribute anything. + +**Q:** I think I've found a bug. How do I report it? + +**A:** The project tracks in-progress tasks and bugs via the JIRA +instance hosted by the Apache Software Foundation: + +https://issues.apache.org/jira/browse/GUACAMOLE/ + +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. + +**Q:** I need help! Where can I find some? + +**A:** 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 +`mailing lists `__. +*You will need to subscribe prior to sending email to any list.* All +mailing lists are actively filtered for spam, and any email not +originating from a subscriber will bounce. + +There are two primary mailing lists: + +user@guacamole.apache.org + The user list is intended for general questions and discussions which + do not necessarily pertain to development. This list replaces the old + `SourceForge + forums `__ used by + Guacamole prior to its acceptance into the Apache Software + Foundation. + + *If you're not sure which mailing list to use, the user list is + probably the correct choice.* + +dev@guacamole.apache.org + The development list is for development-related discussion involving + people who are contributors to the Apache Guacamole project (or who + wish to become contributors). + 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 Binary files a/src/fonts/deja-vu-sans-mono/DejaVuSansMono-Bold.ttf and /dev/null 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 Binary files a/src/fonts/deja-vu-sans-mono/DejaVuSansMono-BoldOblique.ttf and /dev/null 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 Binary files a/src/fonts/deja-vu-sans-mono/DejaVuSansMono-Oblique.ttf and /dev/null 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 Binary files a/src/fonts/deja-vu-sans-mono/DejaVuSansMono.ttf and /dev/null 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 Binary files a/src/fonts/nimbus-roman-no-9-l/n021003l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-roman-no-9-l/n021003l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-roman-no-9-l/n021004l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-roman-no-9-l/n021004l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-roman-no-9-l/n021023l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-roman-no-9-l/n021023l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-roman-no-9-l/n021024l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-roman-no-9-l/n021024l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019003l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019003l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019004l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019004l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019023l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019023l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019024l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019024l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019043l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019043l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019044l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019044l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019063l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019063l.pfm and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019064l.pfb and /dev/null 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 Binary files a/src/fonts/nimbus-sans-l/n019064l.pfm and /dev/null 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 @@ - - - ./ - - ./ - - - - - fonts/deja-vu-sans-mono - fonts/nimbus-roman-no-9-l - fonts/nimbus-sans-l - - - - - diff --git a/src/guacamole-common-js.rst b/src/guacamole-common-js.rst new file mode 100644 index 0000000..1124b10 --- /dev/null +++ b/src/guacamole-common-js.rst @@ -0,0 +1,417 @@ +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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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. + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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 response. to true mouse events. Mouse +events which are actually the result of touch events are ignored. + +.. container:: informalexample + + :: + + 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. + +.. container:: informalexample + + :: + + 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. + +.. container:: informalexample + + :: + + 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 ```` and ```` tags respectively, where each can be +nested within the other as desired. + +Each key is represented with a ```` tag, but this is not what the +user sees, nor what generates the key event. Each key contains any +number of ```` 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: + +.. container:: informalexample + + :: + + + + + Shift + + + a + A + + + + +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: + +.. container:: informalexample + + :: + + // 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 ```` + tags in the keyboard layout. ```` 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 ```` element in + the layout XML. + +``guac-keyboard-requires-MODIFIER`` + Added to the cap element when that cap requires a specific modifier. + +``guac-keyboard-uses-MODIFIER`` + Added to the key element when any cap contained within it requires a + specific modifier. + +``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. + +.. container:: informalexample + + :: + + // 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.rst b/src/guacamole-common.rst new file mode 100644 index 0000000..b14f945 --- /dev/null +++ b/src/guacamole-common.rst @@ -0,0 +1,148 @@ +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 translated 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 created 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: + +.. container:: informalexample + + :: + + 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-ext.rst b/src/guacamole-ext.rst new file mode 100644 index 0000000..a29e6d8 --- /dev/null +++ b/src/guacamole-ext.rst @@ -0,0 +1,781 @@ +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: + ++-----------------+-----------------------------------------------------+ +| Property | Description | ++=================+=====================================================+ +| g | The version string of the Guacamole release that | +| uacamoleVersion | 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 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 ``app/ext/NAMESPACE/PATH``, | +| | where is the value of the namespace | +| | property, and 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: + +.. container:: informalexample + + :: + + { + "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: + +.. container:: informalexample + + :: + + { + + "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: + +.. container:: informalexample + + :: + + + +where is a CSS selector that matches the elements within the +Guacamole interface that serve as a basis for the modification, and + is any one of the following defined modifications: + ++-------------+--------------------------------------------------------+ +| Name | Description | ++=============+========================================================+ +| 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. | ++-------------+--------------------------------------------------------+ +| befo | Inserts the specified HTML immediately before the | +| re-children | 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. | ++-------------+--------------------------------------------------------+ +| aft | Inserts the specified HTML immediately after the last | +| er-children | 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. | ++-------------+--------------------------------------------------------+ +| repla | Replaces the entire contents of any element matching | +| ce-children | 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: + +.. container:: informalexample + + :: + + + +
+

Welcome to our Guacamole server!

+

+ Please be sure to read our privacy + policy before continuing. +

+
+ +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 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: + ++-------------------+---------+----------------------------------------+ +| Class Name | Value | Interpretation | +| | Type | | ++===================+=========+========================================+ +| ``BooleanGu | ``Bo | The values "true" and "false" are | +| acamoleProperty`` | olean`` | parsed as their corresponding | +| | | ``Boolean`` values. Any other value | +| | | results in a parse error. | ++-------------------+---------+----------------------------------------+ +| ``IntegerGu | ``In | Numeric strings are parsed as | +| acamoleProperty`` | teger`` | ``Integer`` values. Non-numeric | +| | | strings will result in a parse error. | ++-------------------+---------+----------------------------------------+ +| ``LongGu | ` | Numeric strings are parsed as ``Long`` | +| acamoleProperty`` | `Long`` | values. Non-numeric strings will | +| | | result in a parse error. | ++-------------------+---------+----------------------------------------+ +| ``StringGu | ``S | The property value is returned as an | +| acamoleProperty`` | tring`` | untouched ``String``. No parsing is | +| | | performed, and parse errors cannot | +| | | occur. | ++-------------------+---------+----------------------------------------+ +| ``FileGu | ` | The property is interpreted as a | +| acamoleProperty`` | `File`` | 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: + +.. container:: informalexample + + :: + + 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(): + +.. container:: informalexample + + :: + + 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``: + +.. container:: informalexample + + :: + + 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 +`/api/ext/ `__, and the root resource for the ``UserContext`` +is exposed at `/api/session/ext/ `__, where is +the path to which Guacamole has been deployed (typically +`/guacamole/
`__) and 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/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 @@ - - - - Guacamole Manual - 1.3.0 - - 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. - - - - 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, and an online - version 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 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. - - Guacamole - history - - - What is Guacamole? - - Guacamole - definition - - 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. - - RealMint - - 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. - - - 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 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. - - - 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. - - - 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 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. - - - - User's Guide - - - - - - - - - - - - - - - - - - - - - Developer's Guide - - - - - - - - - - - - Appendices - - - - - diff --git a/src/header-auth.rst b/src/header-auth.rst new file mode 100644 index 0000000..693c653 --- /dev/null +++ b/src/header-auth.rst @@ -0,0 +1,89 @@ +.. _header-auth: + +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 <#configuring-guacamole>`__\ *before +proceeding.* + +To install the HTTP header authentication extension, you must: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- Copy ``guacamole-auth-header-1.2.0.jar`` within + ``GUACAMOLE_HOME/extensions``. + +- 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 diff --git a/src/index.rst b/src/index.rst new file mode 100644 index 0000000..4d38326 --- /dev/null +++ b/src/index.rst @@ -0,0 +1,76 @@ +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 + + architecture + installing + docker + reverse-proxy + configuring + jdbc-auth + ldap-auth + duo-auth + totp-auth + header-auth + cas-auth + openid-auth + saml-auth + radius-auth + adhoc-connections + using + administration + troubleshooting + +.. toctree:: + :caption: Developer's Guide + :name: developers-guide + :maxdepth: 1 + + protocol + libguac + guacamole-common + guacamole-common-js + guacamole-ext + adding-protocol + custom-auth + event-listeners + yourown + +.. toctree:: + :caption: Appendices + :name: appendices + :maxdepth: 1 + + faq + protocol-reference + diff --git a/src/installing.rst b/src/installing.rst new file mode 100644 index 0000000..e586205 --- /dev/null +++ b/src/installing.rst @@ -0,0 +1,789 @@ +.. _installing-guacamole: + +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 +`Tomcat `__. + +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 ``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, +libpng, and the OSSP UUID library. These libraries are strictly required +*in all cases* - Guacamole cannot be built without them. + ++--------------+--------------------------------------------------------+ +| Library name | Features | ++==============+========================================================+ +| ` | Cairo is used by libguac for graphics rendering. | +| Cairo `__ | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libcairo2-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | cairo-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `libjpe | libjpeg-turbo is used by libguac to provide JPEG | +| g-turbo `__ | +-------------------------+-------------------------+ | +| | | Debian package | libjpeg62-turbo-dev | | +| | +-------------------------+-------------------------+ | +| | | Ubuntu package | libjpeg-turbo8-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libjpeg-turbo-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | +| | | +| | If libjpeg-turbo is unavailable on your platform, and | +| | you do not wish to build it from source, | +| | `libjpeg `__ will work as well, | +| | though it will not be quite as fast: | +| | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libjpeg62-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libjpeg-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `libpn | libpng is used by libguac to write PNG images, the | +| g `__ | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libpng12-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libpng-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `libtool < | libtool is used during the build process. libtool | +| https://www. | creates compiled libraries needed for Guacamole. | +| gnu.org/soft | | +| ware/libtool | +-------------------------+-------------------------+ | +| /manual/libt | | Debian / Ubuntu package | libtool-bin | | +| ool.html>`__ | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libtool | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| libuuid | libuuid is used by libguac to assign unique, internal | +| (part of | IDs to each Guacamole user and connection. These | +| `util-li | unique IDs are the basis for connection sharing | +| nux `__) | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libuuid-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | +| | | +| | If libuuid is unavailable, the `OSSP | +| | UUID `__ library | +| | may also be used: | +| | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libossp-uuid-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | uuid-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ + +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 (1.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. + ++--------------+--------------------------------------------------------+ +| Library name | Features | ++==============+========================================================+ +| `FFmpeg | The libavcodec, libavformat, libavutil, and libswscale | +| `__ | 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. | +| | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libavcodec-dev, | | +| | | | libavformat-dev, | | +| | | | libavutil-dev, | | +| | | | libswscale-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | ffmpeg-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| ` | FreeRDP 2.0.0 or later is required for RDP support. If | +| FreeRDP `__ | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | freerdp2-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | freerdp-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `Pango `__ | (Kubernetes, SSH, and telnet). If you do not wish to | +| | build any terminal-based protocol support, this | +| | library is not needed. | +| | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libpango1.0-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | pango-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| ` | libssh2 is required for SSH support. If you do not | +| libssh2 `__ | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libssh2-1-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libssh2-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `libtelnet < | libtelnet is required for telnet support. If you do | +| https://gith | not wish to build telnet support, this library is not | +| ub.com/seanm | needed. | +| iddleditch/l | | +| ibtelnet>`__ | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libtelnet-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libtelnet-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `libVNC | libVNCServer provides libvncclient, which is required | +| Server `__ | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libvncserver-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libvncserver-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `libwebsoc | libwebsockets is required for Kubernetes support. If | +| kets `__ | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libwebsockets-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libwebsockets-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `PulseAud | PulseAudio provides libpulse, which is used by | +| io `__ | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libpulse-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | pulseaudio-libs-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `O | OpenSSL provides support for SSL and TLS - two common | +| penSSL `__ | | +| | 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. | +| | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libssl-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | openssl-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `li | libvorbis provides support for Ogg Vorbis - a free and | +| bvorbis `__ | 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. | +| | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libvorbis-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libvorbis-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ +| `libweb | libwebp is used by libguac to write WebP images. | +| p `__ | | +| | Lacking WebP support, Guacamole will simply use JPEG | +| | in cases that it would have preferred WebP. | +| | | +| | +-------------------------+-------------------------+ | +| | | Debian / Ubuntu package | libwebp-dev | | +| | +-------------------------+-------------------------+ | +| | | Fedora / CentOS / RHEL | libwebp-devel | | +| | | package | | | +| | +-------------------------+-------------------------+ | ++--------------+--------------------------------------------------------+ + +.. _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: + +.. container:: informalexample + + :: + + $ 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: + +.. container:: informalexample + + :: + + $ 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: + + .. container:: informalexample + + :: + + $ 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: + +.. container:: informalexample + + :: + + $ ./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: + + .. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + $ make + 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' + $ + +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: + +.. container:: informalexample + + :: + + # make install + 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' + # 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 <#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: + +.. container:: informalexample + + :: + + $ 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: + +.. container:: informalexample + + :: + + $ 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: + +.. container:: informalexample + + :: + + $ 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 +------------------- + +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: + +.. container:: informalexample + + :: + + # 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: + +.. container:: informalexample + + :: + + # 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: + +.. container:: informalexample + + :: + + # /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 <#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.rst b/src/introduction.rst new file mode 100644 index 0000000..5681c6c --- /dev/null +++ b/src/introduction.rst @@ -0,0 +1,165 @@ +.. _preface: + +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, and an online version 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.rst b/src/jdbc-auth.rst new file mode 100644 index 0000000..8bf7ed8 --- /dev/null +++ b/src/jdbc-auth.rst @@ -0,0 +1,1957 @@ +.. _jdbc-auth: + +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 `Associating LDAP with a +database <#ldap-and-database>`__ within `LDAP +authentication <#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 <#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: + +``mysql/`` + Contains the MySQL/MariaDB authentication extension, + ``guacamole-auth-jdbc-mysql-1.3.0.jar``, along with a ``schema/`` + directory containing MySQL-specific SQL scripts required to set up + the database. The ``guacamole-auth-jdbc-mysql-1.3.0.jar`` file will + ultimately need to be placed within ``GUACAMOLE_HOME/extensions``, + while the MySQL JDBC driver must be placed within + ``GUACAMOLE_HOME/lib``. + + *The MySQL JDBC driver is not included with the extension.* You must + obtain a supported JDBC driver ``.jar`` yourself. The MySQL driver + can be downloaded from `MySQL's + website `__, and is + known as "Connector/J". The required ``.jar`` will be within a + ``.tar.gz`` archive. + + 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. + + The mysql-driver 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 mysql-driver property: + + mysql + The MySQL JDBC driver, known as Connector/J. This is the default. + + mariadb + The MariaDB JDBC driver. + + The mysql-server-timezone 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: + + Region/Locale + Well-known TimeZone Identifiers, in the Region/Locale format. + Examples are: + + .. container:: informalexample + + :: + + 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: + + .. container:: informalexample + + :: + + 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: + + .. container:: informalexample + + :: + + 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.* + + Configuration parameters for MySQL-compatible SSL support are as + follows: + + +--------------+-------------------------------------------------------+ + | Property | Description | + +==============+=======================================================+ + | my | This property sets the SSL mode that the JDBC driver | + | sql-ssl-mode | 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 | The file that will store trusted SSL certificates for | + | -trust-store | 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-tr | The password to use to access the SSL trusted | + | ust-password | certificate store, if one is required. By default no | + | | password will be used. | + +--------------+-------------------------------------------------------+ + | mysql-ssl- | The file that contains the client certificate to use | + | client-store | 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. | + +--------------+-------------------------------------------------------+ + | m | The password to use to access the client certificate | + | ysql-ssl-cli | store, if one is required. By default no password | + | ent-password | will be used. | + +--------------+-------------------------------------------------------+ + +``postgresql/`` + Contains the PostgreSQL authentication extension, + ``guacamole-auth-jdbc-postgresql-1.3.0.jar``, along with a + ``schema/`` directory containing PostgreSQL-specific SQL scripts + required to set up the database. The + ``guacamole-auth-jdbc-postgresql-1.3.0.jar`` file will ultimately + need to be placed within ``GUACAMOLE_HOME/extensions``, while the + PostgreSQL JDBC driver must be placed within ``GUACAMOLE_HOME/lib``. + + *The PostgreSQL JDBC driver is not included with the extension.* You + must obtain the JDBC driver ``.jar`` yourself from `PostgreSQL's + website `__. The + proper ``.jar`` file depends on the version of Java you have + installed. + + 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: + + +--------------+-------------------------------------------------------+ + | Property | Description | + +==============+=======================================================+ + | postgre | This property sets the SSL mode that the JDBC | + | sql-ssl-mode | 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 authoritiers. | + | | | + | | 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-s | The file containing the client certificate to be used | + | sl-cert-file | 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- | The file containing the client private key to be used | + | ssl-key-file | 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. | + +--------------+-------------------------------------------------------+ + | postg | The file containing the root and intermedidate | + | resql-ssl-ro | certificates against which the server certificate | + | ot-cert-file | 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. | + +--------------+-------------------------------------------------------+ + | pos | The password that will be used to access the client | + | tgresql-ssl- | private key file, if the client private key is | + | key-password | encrypted. This property is optional, and is only | + | | used if the postgresql-ssl-key-file property is set | + | | and SSL is enabled. | + +--------------+-------------------------------------------------------+ + + The PostgreSQL extension also implements some parameters to configure + timeouts at the database and network level. The parameters are as + follows: + + +--------------+-------------------------------------------------------+ + | Property | Description | + +==============+=======================================================+ + | postgresql-d | The number of seconds the driver will wait for a | + | efault-state | response from the database, before aborting the | + | ment-timeout | query. A value of 0 (the default) means the timeout | + | | is disabled. | + +--------------+-------------------------------------------------------+ + | p | The number of seconds to wait for socket read | + | ostgresql-so | operations. If reading from the server takes longer | + | cket-timeout | 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. | + +--------------+-------------------------------------------------------+ + +``sqlserver/`` + Contains the SQL Server authentication extension, + ``guacamole-auth-jdbc-sqlserver-1.3.0.jar``, along with a ``schema/`` + directory contains SQL Server-specific scripts requires to set up the + database. The JAR extension file will need to be placed within the + ``GUACAMOLE_HOME/extensions`` folder, while the SQL Server JDBC + driver must be placed within the ``GUACAMOLE_HOME/lib`` directory. + + *The SQL Server JDBC driver is not included with the extension.* You + must obtain the JDBC driver ``.jar`` 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 ``.jar`` is in the correct + directory. Microsoft's JDBC driver can be downloaded from Microsoft's + `SQL Connection + Libraries `__ + page. + + In addition to the various parameters mentioned below, the SQL Server + driver implements two parameters to control SQL Server-specific + configuration items: sqlserver-driver and sqlserver-instance. + + The sqlserver-instance 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. + + The sqlserver-driver 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 sqlserver-driver property: + + microsoft2005 + The current Microsoft driver, supporting SQL Server 2005 and + later. + + microsoft + The legacy SQL Server support. + + jtds + The open source JTDS driver. + + datadirect + The Progress Sybase driver. + +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. + +.. _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. + +.. _jdbc-auth-mysql: + +MySQL +~~~~~ + +.. container:: informalexample + + :: + + $ ls schema/ + 001-create-schema.sql 002-create-admin-user.sql upgrade + $ cat schema/*.sql | mysql -u root -p guacamole_db + Enter password: password + $ + +.. _jdbc-auth-postgresql: + +PostgreSQL +~~~~~~~~~~ + +.. container:: informalexample + + :: + + $ 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 + $ + +.. _jdbc-auth-sqlserver: + +SQL Server +~~~~~~~~~~ + +.. container:: informalexample + + :: + + $ /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -d guacamole_db -i schema/001-create-schema.sql + Password: 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: password + + (1 rows affected) + + (3 rows affected) + + (5 rows affected) + +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 +``upgrade-pre-VERSION.sql`` where 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 . + +If there are no ``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:: + :name: jdbc-auth-postgresql-upgrade + + 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: + + .. container:: informalexample + + :: + + $ 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 + $ + +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. + +MySQL +~~~~~ + +.. container:: informalexample + + :: + + $ mysql -u root -p + Enter password: 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> 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 + $ + +PostgreSQL +~~~~~~~~~~ + +.. container:: informalexample + + :: + + $ 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 + $ + +SQL Server +~~~~~~~~~~ + +.. container:: informalexample + + :: + + $ /opt/mssql-tools/bin/sqlcmd -S localhost -U SA + Password: password + 1> CREATE DATABASE guacamole_db; + 2> GO + 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 + +.. _jdbc-auth-installation: + +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: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- 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. + +- 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. + +- 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. + +To use a MySQL database, you will need to specify the following: + +.. container:: informalexample + + :: + + # MySQL properties + mysql-hostname: localhost + mysql-port: 3306 + mysql-database: guacamole_db + mysql-username: guacamole_user + mysql-password: some_password + + +For PostgreSQL, the properties are similar, but with different prefixes: + +.. container:: informalexample + + :: + + # PostgreSQL properties + postgresql-hostname: localhost + postgresql-port: 5432 + postgresql-database: guacamole_db + postgresql-username: guacamole_user + postgresql-password: some_password + + +The SQL Server properties follow the same format: + +.. container:: informalexample + + :: + + # SQL Server properties + sqlserver-hostname: localhost + sqlserver-port: 1433 + sqlserver-database: guacamole_db + sqlserver-username: guacamole_user + sqlserver-password: some_password + sqlserver-driver: microsoft2005 + + +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: + ++-------------+-------------+-------------+---------------------------+ +| My | PostgreSQL | SQL Server | Description | +| SQL/MariaDB | Property | Property | | +| Property | | | | ++=============+=============+=============+===========================+ +| mys | postgres | sqlserv | The hostname or IP | +| ql-hostname | ql-hostname | er-hostname | address of the server | +| | | | hosting your database. | ++-------------+-------------+-------------+---------------------------+ +| mysql-port | post | sql | The port number of the | +| | gresql-port | server-port | database to connect to. | +| | | | For MySQL and MariaDB, | +| | | | this will likely be 3306. | +| | | | For PostgreSQL, this will | +| | | | likely be 5432. | ++-------------+-------------+-------------+---------------------------+ +| mys | postgres | sqlserv | The name of the database | +| ql-database | ql-database | er-database | that you created for | +| | | | Guacamole. This is given | +| | | | as "guacamole_db" in the | +| | | | examples given in this | +| | | | chapter. | ++-------------+-------------+-------------+---------------------------+ +| mys | postgres | sqlserv | The username of the user | +| ql-username | ql-username | er-username | that Guacamole should use | +| | | | to connect to the | +| | | | database. This is given | +| | | | as "guacamole_user" in | +| | | | the examples given in | +| | | | this chapter. | ++-------------+-------------+-------------+---------------------------+ +| mys | postgres | sqlserv | The password Guacamole | +| ql-password | ql-password | er-password | should provide when | +| | | | authenticating with the | +| | | | database. This is given | +| | | | as "some_password" in the | +| | | | examples given in this | +| | | | chapter. | ++-------------+-------------+-------------+---------------------------+ + +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. + +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 `__, 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. + +.. container:: informalexample + + :: + + # 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 + + # 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 + + # 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: + +.. container:: informalexample + + :: + + # MySQL + mysql-user-password-min-age: 7 + mysql-user-password-max-age: 90 + + # PostgreSQL + postgresql-user-password-min-age: 7 + postgresql-user-password-max-age: 90 + + # 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. + +.. container:: informalexample + + :: + + # MySQL + mysql-user-password-history-size: 6 + + # PostgreSQL + postgresql-user-password-history-size: 6 + + # 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: + +.. container:: informalexample + + :: + + # 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 + +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: + +.. container:: informalexample + + :: + + # 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 + +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: + +.. container:: informalexample + + :: + + # MySQL + mysql-absolute-max-connections: 0 + + # PostgreSQL + postgresql-absolute-max-connections: 0 + + # 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: + +.. container:: informalexample + + :: + + # MySQL + mysql-user-required: true + + # PostgreSQL + postgresql-user-required: true + + # 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. + +.. container:: informalexample + + :: + + # MySQL + mysql-auto-create-accounts: true + + # PostgreSQL + postgresql-auto-create-accounts: true + + # 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 <#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() `__, + 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: + +.. container:: informalexample + + :: + + -- 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`` with the + mysql-default-max-connections or postgresql-default-max-connections + 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`` with the + mysql-default-max-connections or postgresql-default-max-connections + 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: + +.. container:: informalexample + + :: + + -- 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`` with the + mysql-default-max-connections or postgresql-default-max-connections + 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`` with the + mysql-default-max-connections or postgresql-default-max-connections + 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: + +.. container:: informalexample + + :: + + -- 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: + +lSystem 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.rst b/src/ldap-auth.rst new file mode 100644 index 0000000..5bb8688 --- /dev/null +++ b/src/ldap-auth.rst @@ -0,0 +1,625 @@ +.. _ldap-auth: + +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 + :ref:`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 `__. + +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 `Database authentication <#jdbc-auth>`__ and later in + this chapter in `Associating LDAP with a + database <#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 +`Associating LDAP with a database <#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 ``ldapadd`` utility +with the provided ``guacConfigGroup.ldif`` file: + +.. container:: informalexample + + :: + + # 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 ``ldapsearch``: + +.. container:: informalexample + + :: + + # 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 `Database +authentication <#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: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- Copy ``guacamole-auth-ldap-1.3.0.jar`` within + ``GUACAMOLE_HOME/extensions``. + +- 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 + + .. container:: informalexample + + :: + + 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 + + .. container:: informalexample + + :: + + 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 `__". + For example: + + .. table:: Example LDAP attribute / parameter token conversions + + +-----------------------------------+-----------------------------------+ + | 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}`` | + +-----------------------------------+-----------------------------------+ + | ``a | ``${LDAP_A_RAND | + | RANDOM_mixOf-3NAMINGConventions`` | OM_MIX_OF_3_NAMING_CONVENTIONS}`` | + +-----------------------------------+-----------------------------------+ + + Usage of parameter tokens is discussed in more detail in `Configuring + Guacamole <#configuring-guacamole>`__ in `Parameter + tokens <#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 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. + +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: + +.. container:: informalexample + + :: + + 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 ``ldapadd`` utility: + +.. container:: informalexample + + :: + + $ 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 `__, which make many of the +tasks given above much easier. + diff --git a/src/libguac.rst b/src/libguac.rst new file mode 100644 index 0000000..e488152 --- /dev/null +++ b/src/libguac.rst @@ -0,0 +1,457 @@ +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 + libguac-client-. *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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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 to 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-stream-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 `Streams and +objects <#guacamole-protocol-streaming>`__ and +`appendix_title <#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 guac_protocol_send_(). + +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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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. + +.. container:: informalexample + + :: + + 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. + +.. container:: informalexample + + :: + + 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. + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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.rst b/src/openid-auth.rst new file mode 100644 index 0000000..c402845 --- /dev/null +++ b/src/openid-auth.rst @@ -0,0 +1,172 @@ +.. _openid-auth: + +OpenID Connect Authentication +============================= + +`OpenID Connect `__ is a widely-adopted open +standard for implementing single sign-on (SSO). `Not to be confused with +OAuth `__, 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 `__" +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 <#configuring-guacamole>`__\ *before +proceeding.* + +To install the OpenID Connect authentication extension, you must: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- Copy ``guacamole-auth-openid-1.3.0.jar`` within + ``GUACAMOLE_HOME/extensions``. + +- 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 `__, + this value can be retrieved from the "authorization_endpoint" + property of the JSON file hosted at + `/.well-known/openid-configuration `__, + where 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 `__ or JWTs) shall be + validated. + + This value should be provided to you by the identity provider. For + identity providers that implement `OpenID Connect + Discovery `__, + this value can be retrieved from the "jwks_uri" property of the JSON + file hosted at + `/.well-known/openid-configuration `__, + where 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 `__, + this value can be retrieved from the "issuer" property of the JSON + file hosted at + `/.well-known/openid-configuration `__, + where 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..49dcde3 --- /dev/null +++ b/src/protocol-reference.rst @@ -0,0 +1,1343 @@ +Guacamole protocol reference +============================ + +Drawing instructions +-------------------- + +.. _arc-instruction: + +arc +~~~ + +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. + +``layer`` + The layer which should have the specified arc subpath added. + +``x`` + The X coordinate of the center of the circle containing the arc to be + drawn. + +``y`` + The Y coordinate of the center of the circle containing the arc to be + drawn. + +``radius`` + The radius of the circle containing the arc to be drawn, in pixels. + +``start`` + The starting angle of the arc to be drawn, in radians. + +``end`` + The ending angle of the arc to be drawn, in radians. + +``negative`` + Non-zero if the arc should be drawn from START to END in order of + decreasing angle, zero otherwise. + +.. _cfill-instruction: + +cfill +~~~~~ + +Fills the current path with the specified color. This instruction +completes the current path. Future path instructions will begin a new +path. + +``mask`` + The channel mask to apply when filling the current path in the + specified layer. + +``layer`` + The layer whose path should be filled. + +``r`` + The red component of the color to use to fill the current path in the + specified layer. + +``g`` + The green component of the color to use to fill the current path in + the specified layer. + +``b`` + The blue component of the color to use to fill the current path in + the specified layer. + +``a`` + The alpha component of the color to use to fill the current path in + the specified layer. + +.. _clip-instruction: + +clip +~~~~ + +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. + +``layer`` + The layer whose clipping path should be set. + +.. _close-instruction: + +close +~~~~~ + +Closes the current path by connecting the start and end points with a +straight line. + +``layer`` + The layer whose path should be closed. + +.. _copy-instruction: + +copy +~~~~ + +Copies image data from the specified rectangle of the specified layer or +buffer to a different location of another specified layer or buffer. + +``srclayer`` + The index of the layer to copy image data from. + +``srcx`` + The X coordinate of the upper-left corner of the source rectangle + within the source layer. + +``srcy`` + The Y coordinate of the upper-left corner of the source rectangle + within the source layer. + +``srcwidth`` + The width of the source rectangle within the source layer. + +``srcheight`` + The height of the source rectangle within the source layer. + +``mask`` + The channel mask to apply when drawing the image data on the + destination layer. + +``dstlayer`` + The index of the layer to draw the image data to. + +``dstx`` + The X coordinate of the upper-left corner of the destination within + the destination layer. + +``dsty`` + The Y coordinate of the upper-left corner of the destination within + the destination layer. + +.. _cstroke-instruction: + +cstroke +~~~~~~~ + +Strokes the current path with the specified color. This instruction +completes the current path. Future path instructions will begin a new +path. + +``mask`` + The channel mask to apply when stroking the current path in the + specified layer. + +``layer`` + The layer whose path should be stroked. + +``cap`` + The index of the line cap style to use. This can be either butt (0), + round (1), or square (2). + +``join`` + The index of the line join style to use. This can be either bevel + (0), miter (1), or round (2). + +``thickness`` + The thickness of the stroke to draw, in pixels. + +``r`` + The red component of the color to use to stroke the current path in + the specified layer. + +``g`` + The green component of the color to use to stroke the current path in + the specified layer. + +``b`` + The blue component of the color to use to stroke the current path in + the specified layer. + +``a`` + The alpha component of the color to use to stroke the current path in + the specified layer. + +.. _cursor-instruction: + +cursor +~~~~~~ + +Sets the client's cursor to the image data from the specified rectangle +of a layer, with the specified hotspot. + +``x`` + The X coordinate of the cursor's hotspot. + +``y`` + The Y coordinate of the cursor's hotspot. + +``srclayer`` + The index of the layer to copy image data from. + +``srcx`` + The X coordinate of the upper-left corner of the source rectangle + within the source layer. + +``srcy`` + The Y coordinate of the upper-left corner of the source rectangle + within the source layer. + +``srcwidth`` + The width of the source rectangle within the source layer. + +``srcheight`` + The height of the source rectangle within the source layer. + +.. _curve-instruction: + +curve +~~~~~ + +Adds the specified cubic bezier curve subpath. + +``layer`` + The layer which should have the specified curve subpath added. + +``cp1x`` + The X coordinate of the first control point of the curve. + +``cp1y`` + The Y coordinate of the first control point of the curve. + +``cp2x`` + The X coordinate of the second control point of the curve. + +``cp2y`` + The Y coordinate of the second control point of the curve. + +``x`` + The X coordinate of the endpoint of the curve. + +``y`` + The Y coordinate of the endpoint of the curve. + +.. _dispose-instruction: + +dispose +~~~~~~~ + +Removes the specified layer. The specified layer will be recreated as a +new layer if it is referenced again. + +``layer`` + The layer to remove. + +.. _distort-instruction: + +distort +~~~~~~~ + +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 + +``layer`` + The layer to distort. + +``a`` + The matrix value in row 1, column 1. + +``b`` + The matrix value in row 2, column 1. + +``c`` + The matrix value in row 1, column 2. + +``d`` + The matrix value in row 2, column 2. + +``e`` + The matrix value in row 1, column 3. + +``f`` + The matrix value in row 2, column 3. + +.. _identity-instruction: + +identity +~~~~~~~~ + +Resets the transform matrix of the specified layer to the identity +matrix. + +``layer`` + The layer whose transform matrix should be reset. + +.. _lfill-instruction: + +lfill +~~~~~ + +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. + +``mask`` + The channel mask to apply when filling the current path in the + specified layer. + +``layer`` + The layer whose path should be filled. + +``srclayer`` + The layer to use as the pattern. + +.. _line-instruction: + +line +~~~~ + +Adds the specified line subpath. + +``layer`` + The layer which should have the specified line subpath added. + +``x`` + The X coordinate of the endpoint of the line. + +``y`` + The Y coordinate of the endpoint of the line. + +.. _lstroke-instruction: + +lstroke +~~~~~~~ + +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. + +``mask`` + The channel mask to apply when filling the current path in the + specified layer. + +``layer`` + The layer whose path should be filled. + +``cap`` + The index of the line cap style to use. This can be either butt (0), + round (1), or square (2). + +``join`` + The index of the line join style to use. This can be either bevel + (0), miter (1), or round (2). + +``thickness`` + The thickness of the stroke to draw, in pixels. + +``srclayer`` + The layer to use as the pattern. + +.. _move-instruction: + +move +~~~~ + +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. + +``layer`` + The layer to move. + +``parent`` + The layer that should be the parent of the given layer. + +``x`` + The X coordinate to move the layer to. + +``y`` + The Y coordinate to move the layer to. + +``z`` + The relative Z-ordering of this layer. Layers with larger values will + appear above layers with smaller values. + +.. _pop-instruction: + +pop +~~~ + +Restores the previous state of the specified layer from the stack. The +state restored includes the transformation matrix and clipping path. + +``layer`` + The layer whose state should be restored. + +.. _push-instruction: + +push +~~~~ + +Saves the current state of the specified layer to the stack. The state +saved includes the current transformation matrix and clipping path. + +``layer`` + The layer whose state should be saved. + +.. _rect-instruction: + +rect +~~~~ + +Adds a rectangular path to the specified layer. + +``mask`` + The channel mask to apply when drawing the image data. + +``layer`` + The destination layer. + +``x`` + The X coordinate of the upper-left corner of the rectangle to draw. + +``y`` + The Y coordinate of the upper-left corner of the rectangle to draw. + +``width`` + The width of the rectangle to draw. + +``height`` + The width of the rectangle to draw. + +.. _reset-instruction: + +reset +~~~~~ + +Resets the transformation and clip state of the layer. + +``layer`` + The layer whose state should be reset. + +.. _set-instruction: + +set +~~~ + +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). + +``layer`` + The layer whose property should be set. + +``property`` + The name of the property to set. + +``value`` + The value to set the given property to. + +.. _shade-instruction: + +shade +~~~~~ + +Sets the opacity of the given layer. + +``layer`` + The layer whose opacity should be set. + +``opacity`` + The opacity of the layer, where 0 is completely transparent, and 255 + is completely opaque. + +.. _size-instruction: + +size +~~~~ + +Sets the size of the specified layer. + +``layer`` + The layer to resize. + +``width`` + The new width of the layer + +``height`` + The new height of the layer + +.. _start-instruction: + +start +~~~~~ + +Starts a new subpath at the specified point. + +``layer`` + The layer which should start a new subpath. + +``x`` + The X coordinate of the first point of the new subpath. + +``y`` + The Y coordinate of the first point of the new subpath. + +.. _transfer-instruction: + +transfer +~~~~~~~~ + +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`` `__ +header included with libguac. + +``srclayer`` + The index of the layer to transfer image data from. + +``srcx`` + The X coordinate of the upper-left corner of the source rectangle + within the source layer. + +``srcy`` + The Y coordinate of the upper-left corner of the source rectangle + within the source layer. + +``srcwidth`` + The width of the source rectangle within the source layer. + +``srcheight`` + The height of the source rectangle within the source layer. + +``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`` `__ + header included with libguac. + +``dstlayer`` + The index of the layer to draw the image data to. + +``dstx`` + The X coordinate of the upper-left corner of the destination within + the destination layer. + +``dsty`` + The Y coordinate of the upper-left corner of the destination within + the destination layer. + +.. _transform-instruction: + +transform +~~~~~~~~~ + +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. + +``layer`` + The layer to apply the given transformation matrix to. + +``a`` + The matrix value in row 1, column 1. + +``b`` + The matrix value in row 2, column 1. + +``c`` + The matrix value in row 1, column 2. + +``d`` + The matrix value in row 2, column 2. + +``e`` + The matrix value in row 1, column 3. + +``f`` + The matrix value in row 2, column 3. + +Streaming instructions +---------------------- + +.. _ack-instruction: + +ack +~~~ + +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 ``SUCCESS`` +implicitly ends the stream. + +``stream`` + The index of the stream the corresponding blob was received on. + +``message`` + A human-readable error message. This typically is not exposed within + any user interface, and mainly helps with debugging. + +``status`` + The Guacamole status code denoting success or failure. + +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. + ++-----+----------------+-----------------------------------------------+ +| C | Name | Description | +| ode | | | ++=====+================+===============================================+ +| 0 | ``SUCCESS`` | The operation succeeded. No error. | ++-----+----------------+-----------------------------------------------+ +| 256 | ` | The requested operation is unsupported. | +| | `UNSUPPORTED`` | | ++-----+----------------+-----------------------------------------------+ +| 512 | `` | An internal error occurred, and the operation | +| | SERVER_ERROR`` | could not be performed. | ++-----+----------------+-----------------------------------------------+ +| 513 | ` | The operation could not be performed because | +| | `SERVER_BUSY`` | the server is busy. | ++-----+----------------+-----------------------------------------------+ +| 514 | ``UPST | The upstream server is not responding. In | +| | REAM_TIMEOUT`` | most cases, the upstream server is the remote | +| | | desktop server. | ++-----+----------------+-----------------------------------------------+ +| 515 | ``UP | The upstream server encountered an error. In | +| | STREAM_ERROR`` | most cases, the upstream server is the remote | +| | | desktop server. | ++-----+----------------+-----------------------------------------------+ +| 516 | ``RESOUR | An associated resource, such as a file or | +| | CE_NOT_FOUND`` | stream, could not be found, and thus the | +| | | operation failed. | ++-----+----------------+-----------------------------------------------+ +| 517 | ``RESOU | A resource is already in use or locked, | +| | RCE_CONFLICT`` | preventing the requested operation. | ++-----+----------------+-----------------------------------------------+ +| 518 | ``RES | The requested operation cannot continue | +| | OURCE_CLOSED`` | because the associated resource has been | +| | | closed. | ++-----+----------------+-----------------------------------------------+ +| 519 | ``UPSTRE | The upstream server does not appear to exist, | +| | AM_NOT_FOUND`` | or cannot be reached over the network. In | +| | | most cases, the upstream server is the remote | +| | | desktop server. | ++-----+----------------+-----------------------------------------------+ +| 520 | ``UPSTREAM | The upstream server is refusing to service | +| | _UNAVAILABLE`` | connections. In most cases, the upstream | +| | | server is the remote desktop server. | ++-----+----------------+-----------------------------------------------+ +| 521 | ``SESS | The session within the upstream server has | +| | ION_CONFLICT`` | ended because it conflicts with another | +| | | session. In most cases, the upstream server | +| | | is the remote desktop server. | ++-----+----------------+-----------------------------------------------+ +| 522 | ``SES | The session within the upstream server has | +| | SION_TIMEOUT`` | ended because it appeared to be inactive. In | +| | | most cases, the upstream server is the remote | +| | | desktop server. | ++-----+----------------+-----------------------------------------------+ +| 523 | ``SE | The session within the upstream server has | +| | SSION_CLOSED`` | been forcibly closed. In most cases, the | +| | | upstream server is the remote desktop server. | ++-----+----------------+-----------------------------------------------+ +| 768 | ``CLIENT | The parameters of the request are illegal or | +| | _BAD_REQUEST`` | otherwise invalid. | ++-----+----------------+-----------------------------------------------+ +| 769 | ``CLIENT_ | Permission was denied, because the user is | +| | UNAUTHORIZED`` | 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 | ``CLIE | Permission was denied, and logging in will | +| | NT_FORBIDDEN`` | not solve the problem. | ++-----+----------------+-----------------------------------------------+ +| 776 | ``CL | The client (usually the user of Guacamole or | +| | IENT_TIMEOUT`` | their browser) is taking too long to respond. | ++-----+----------------+-----------------------------------------------+ +| 781 | ``CL | The client has sent more data than the | +| | IENT_OVERRUN`` | protocol allows. | ++-----+----------------+-----------------------------------------------+ +| 783 | ``CLI | The client has sent data of an unexpected or | +| | ENT_BAD_TYPE`` | illegal type. | ++-----+----------------+-----------------------------------------------+ +| 797 | ``CLI | The client is already using too many | +| | ENT_TOO_MANY`` | resources. Existing resources must be freed | +| | | before further requests are allowed. | ++-----+----------------+-----------------------------------------------+ + +.. _argv-instruction: + +argv +~~~~ + +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. + +``stream`` + The index of the stream to allocate. + +``mimetype`` + The mimetype of the connection parameter being sent. In most cases, + this will be "text/plain". + +``name`` + The name of the connection parameter whose value is being sent. + +.. _audio-stream-instruction: + +audio +~~~~~ + +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. + +``stream`` + The index of the stream to allocate. + +``mimetype`` + The mimetype of the audio data being sent. + +.. _blob-instruction: + +blob +~~~~ + +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. + +``stream`` + The index of the stream along which the given data should be sent. + +``data`` + The base64-encoded data to send. + +.. _clipboard-instruction: + +clipboard +~~~~~~~~~ + +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. + +``stream`` + The index of the stream to allocate. + +``mimetype`` + The mimetype of the clipboard data being sent. In most cases, this + will be "text/plain". + +.. _end-instruction: + +end +~~~ + +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. + +``stream`` + The index of the stream the corresponding blob was received on. + +.. _file-stream-instruction: + +file +~~~~ + +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. + +``stream`` + The index of the stream to allocate. + +``mimetype`` + The mimetype of the file being sent. + +``filename`` + The name of the file, as it would be saved on a filesystem. + +.. _img-instruction: + +img +~~~ + +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. + +``stream`` + The index of the stream to allocate. + +``mimetype`` + The mimetype of the image being sent. + +``mask`` + The channel mask to apply when drawing the image data. + +``layer`` + The destination layer. + +``x`` + The X coordinate of the upper-left corner of the destination within + the destination layer. + +``y`` + The Y coordinate of the upper-left corner of the destination within + the destination layer. + +.. _nest-stream-instruction: + +nest +~~~~ + +.. important:: + + *The ``nest`` instruction has been deprecated.* + + The ``nest`` instruction is no longer necessary, having been replaced + by other streaming instructions (such as + ```blob`` <#blob-instruction>`__, ```ack`` <#ack-instruction>`__, and + ```end`` <#end-instruction>`__). Code using the ``nest`` instruction + should instead write instructions directly without wrapping those + instructions within ``nest``. + +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. + +``index`` + 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. + +``data`` + The protocol data, containing part of one or more instructions. + +.. _pipe-instruction: + +pipe +~~~~ + +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. + +``stream`` + The index of the stream to allocate. + +``mimetype`` + The mimetype of the data being sent along the pipe. + +``name`` + The arbitrary name of the pipe, which may have special meaning to + client-side code. + +.. _video-stream-instruction: + +video +~~~~~ + +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. + +``stream`` + The index of the stream to allocate. + +``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. + +``mimetype`` + The mimetype of the video data being sent. + +Object instructions +------------------- + +.. _body-object-instruction: + +body +~~~~ + +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. + +``object`` + The index of the object associated with this stream. + +``stream`` + The index of the stream to allocate. + +``mimetype`` + The mimetype of the data being sent. + +``name`` + The name of the stream associated with the object. + +.. _filesystem-object-instruction: + +filesystem +~~~~~~~~~~ + +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. + +``object`` + The index of the object to allocate. + +``name`` + The name of the filesystem. + +.. _get-object-instruction: + +get +~~~ + +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: + +.. container:: informalexample + + :: + + { + "A" : "text/plain", + "B" : "text/plain" + } + +``object`` + The index of the object to request a stream from. + +``name`` + The name of the stream being requested from the given object. + +.. _put-object-instruction: + +put +~~~ + +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. + +``object`` + The index of the object associated with this stream. + +``stream`` + The index of the stream to allocate. + +``mimetype`` + The mimetype of the data being sent. + +``name`` + The name of the stream within the given object to which data is being + sent. + +.. _undefine-object-instruction: + +undefine +~~~~~~~~ + +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. + +``object`` + The index of the object to undefine. + +Client handshake instructions +----------------------------- + +.. _audio-handshake-instruction: + +audio +~~~~~ + +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. + +.. _connect-instruction: + +connect +~~~~~~~ + +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. + +.. _image-handshake-instruction: + +image +~~~~~ + +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. + +.. _select-instruction: + +select +~~~~~~ + +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. + +``ID`` + 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>`__. + +.. _size-handshake-instruction: + +size +~~~~ + +Specifies the client's optimal screen size and resolution. + +``width`` + The optimal screen width. + +``height`` + The optimal screen height. + +``dpi`` + The optimal screen resolution, in approximate DPI. + +.. _timezone-handshake-instruction: + +timezone +~~~~~~~~ + +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. + +``timezone`` + +.. _video-handshake-instruction: + +video +~~~~~ + +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 +----------------------------- + +.. _args-instruction: + +args +~~~~ + +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. + +Client control instructions +--------------------------- + +.. _client-disconnect-instruction: + +disconnect +~~~~~~~~~~ + +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. + +.. _client-nop-instruction: + +nop +~~~ + +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. + +.. _client-sync-instruction: + +sync +~~~~ + +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. + +Both client and server are expected to occasionally send sync to report +on current operation execution state. + +``timestamp`` + A valid server-relative timestamp. + +Server control instructions +--------------------------- + +.. _server-disconnect-instruction: + +disconnect +~~~~~~~~~~ + +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. + +.. _error-instruction: + +error +~~~~~ + +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. + +``text`` + An arbitrary message describing the error + +``status`` + The Guacamole status code describing the error. For a list of status + codes, see the table in `Status codes <#status-codes>`__. + +.. _log-instruction: + +log +~~~ + +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. + +``message`` + An arbitrary, human-readable message. + +.. _server-mouse-instruction: + +mouse +~~~~~ + +Reports that a user on the current connection has moved the mouse to the +given coordinates. + +``x`` + The current X coordinate of the mouse pointer. + +``y`` + The current Y coordinate of the mouse pointer. + +.. _server-nop-instruction: + +nop +~~~ + +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. + +.. _ready-instruction: + +ready +~~~~~ + +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. + +``ID`` + 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"). + +.. _server-sync-instruction: + +sync +~~~~ + +Indicates that the given timestamp is the current timestamp as of all +previous operations. The client must respond to every sync instruction +received. + +Both client and server are expected to occasionally send sync to report +on current operation execution state. + +``timestamp`` + A valid server-relative timestamp. + +Client events +------------- + +.. _key-instruction: + +key +~~~ + +Sends the specified key press or release event. + +``keysym`` + The `X11 keysym `__ of the key being + pressed or released. + +``pressed`` + 0 if the key is not pressed, 1 if the key is pressed. + +.. _client-mouse-instruction: + +mouse +~~~~~ + +Sends the specified mouse movement or button press or release event (or +combination thereof). + +``x`` + The current X coordinate of the mouse pointer. + +``y`` + The current Y coordinate of the mouse pointer. + +``mask`` + The button mask, representing the pressed or released status of each + mouse button. + +.. _size-event-instruction: + +size +~~~~ + +Specifies that the client's optimal screen size has changed from what +was specified during the handshake, or from previously-sent "size" +instructions. + +``width`` + The new, optimal screen width. + +``height`` + The new, optimal screen height. + diff --git a/src/protocol.rst b/src/protocol.rst new file mode 100644 index 0000000..19da11b --- /dev/null +++ b/src/protocol.rst @@ -0,0 +1,454 @@ +.. _guacamole-protocol: + +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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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 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: + ++-----+----------------+-----------------------------------------------+ +| V | Value | Description | +| ers | | | +| ion | | | ++=====+================+===============================================+ +| 1. | ``V | This is the default version and applies to | +| 0.0 | ERSION_1_0_0`` | 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). | ++-----+----------------+-----------------------------------------------+ +| 1. | ``V | Protocol version 1.1.0 introduces support for | +| 1.0 | ERSION_1_1_0`` | protocol version negotiation, arbitrary order | +| | | of the handshake instructions, and support | +| | | for passing the timezone instruction during | +| | | the handshake. | ++-----+----------------+-----------------------------------------------+ + +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. + +.. container:: informalexample + + :: + + 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: + ++--------------+-------------------------------------------------------+ +| Instruction | Description | +| name | | ++==============+=======================================================+ +| ``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 <#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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + 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 `Streams and objects <#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/radius-auth.rst b/src/radius-auth.rst new file mode 100644 index 0000000..1376e8b --- /dev/null +++ b/src/radius-auth.rst @@ -0,0 +1,214 @@ +.. _radius-auth: + +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 natively <#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: + +.. container:: informalexample + + :: + + $ 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 <#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: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- Copy ``guacamole-auth-radius-1.3.0.jar`` into + ``GUACAMOLE_HOME/extensions``. + +- 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 @@ - - -
- disconnect - - - disconnect - - 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. - -
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 @@ - -
- nop - - nop - - 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. -
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 @@ - - -
- sync - - sync - - 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. - Both client and server are expected to occasionally send sync to - report on current operation execution state. - - - timestamp - - A valid server-relative timestamp. - - - -
\ 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 @@ - - -
- key - - - key - - Sends the specified key press or release event. - - - keysym - - The X11 - keysym of the key being pressed or - released. - - - - pressed - - 0 if the key is not pressed, 1 if the key is - pressed. - - - - -
\ 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 @@ - - -
- mouse - - - mouse - - Sends the specified mouse movement or button press or release event (or - combination thereof). - - - x - - The current X coordinate of the mouse pointer. - - - - y - - The current Y coordinate of the mouse pointer. - - - - mask - - The button mask, representing the pressed or released - status of each mouse button. - - - - -
\ 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 @@ - - -
- size - - size - - Specifies that the client's optimal screen size has changed from what was specified during - the handshake, or from previously-sent "size" instructions. - - - width - - The new, optimal screen width. - - - - height - - The new, optimal screen height. - - - -
\ 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 @@ - - -
- audio - - audio - - 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. -
\ 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 @@ - - -
- connect - - - connect - - 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. - -
\ 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 @@ - - -
- image - - image - - 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. -
\ 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 @@ - - -
- select - - - select - - 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) must not collide with any - supported protocols. - This is the first instruction sent during the handshake phase. - - - ID - - 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. - - - - -
\ 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 @@ - - -
- size - - size - - Specifies the client's optimal screen size and resolution. - - - width - - The optimal screen width. - - - - height - - The optimal screen height. - - - - dpi - - The optimal screen resolution, in approximate DPI. - - - -
\ 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 @@ - - -
- timezone - - timezone - - 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. - - - timezone - - A valid IANA time zone key that indicates the time zone - that the client is currently using. - - - -
\ 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 @@ - - -
- video - - video - - 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. -
\ 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 @@ - - -
- disconnect - - disconnect - - 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. -
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 @@ - - -
- error - - - error - - 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. - - - text - - An arbitrary message describing the error - - - - status - - The Guacamole status code describing the error. For a list of status codes, - see the table in . - - - - -
\ 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 @@ - -
- log - - log - - 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. - - - message - - An arbitrary, human-readable message. - - - -
\ 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 @@ - - -
- mouse - - mouse - - Reports that a user on the current connection has moved the mouse to the given - coordinates. - - - x - - The current X coordinate of the mouse pointer. - - - - y - - The current Y coordinate of the mouse pointer. - - - -
\ 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 @@ - -
- nop - - nop - - 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. -
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 @@ - -
- ready - - ready - - 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. - - - ID - - 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"). - - - -
\ 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 @@ - - -
- sync - - sync - - Indicates that the given timestamp is the current timestamp as of all - previous operations. The client must respond to every sync instruction - received. - Both client and server are expected to occasionally send sync to - report on current operation execution state. - - - timestamp - - A valid server-relative timestamp. - - - -
\ 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 @@ - -
- arc - - arc - - 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. - - - layer - - The layer which should have the specified arc subpath - added. - - - - x - - The X coordinate of the center of the circle containing - the arc to be drawn. - - - - y - - The Y coordinate of the center of the circle containing - the arc to be drawn. - - - - radius - - The radius of the circle containing the arc to be drawn, - in pixels. - - - - start - - The starting angle of the arc to be drawn, in - radians. - - - - end - - The ending angle of the arc to be drawn, in - radians. - - - - negative - - Non-zero if the arc should be drawn from START to END in - order of decreasing angle, zero otherwise. - - - -
\ 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 @@ - - -
- cfill - - cfill - - Fills the current path with the specified color. This instruction - completes the current path. Future path instructions will begin a new - path. - - - mask - - The channel mask to apply when filling the current path in - the specified layer. - - - - layer - - The layer whose path should be filled. - - - - r - - The red component of the color to use to fill the current - path in the specified layer. - - - - g - - The green component of the color to use to fill the - current path in the specified layer. - - - - b - - The blue component of the color to use to fill the current - path in the specified layer. - - - - a - - The alpha component of the color to use to fill the - current path in the specified layer. - - - -
\ 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 @@ - - -
- clip - - - clip - - 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. - - - layer - - The layer whose clipping path should be set. - - - - -
\ 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 @@ - - -
- close - - - close - - Closes the current path by connecting the start and end points with a - straight line. - - - layer - - The layer whose path should be closed. - - - - -
\ 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 @@ - - -
- copy - - - copy - - Copies image data from the specified rectangle of the specified layer - or buffer to a different location of another specified layer or - buffer. - - - srclayer - - The index of the layer to copy image data from. - - - - srcx - - The X coordinate of the upper-left corner of the source - rectangle within the source layer. - - - - srcy - - The Y coordinate of the upper-left corner of the source - rectangle within the source layer. - - - - srcwidth - - The width of the source rectangle within the source - layer. - - - - srcheight - - The height of the source rectangle within the source - layer. - - - - mask - - The channel mask to apply when drawing the image data on - the destination layer. - - - - dstlayer - - The index of the layer to draw the image data to. - - - - dstx - - The X coordinate of the upper-left corner of the - destination within the destination layer. - - - - dsty - - The Y coordinate of the upper-left corner of the - destination within the destination layer. - - - - -
\ 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 @@ - - -
- cstroke - - - cstroke - - Strokes the current path with the specified color. This instruction - completes the current path. Future path instructions will begin a new - path. - - - mask - - The channel mask to apply when stroking the current path - in the specified layer. - - - - layer - - The layer whose path should be stroked. - - - - cap - - The index of the line cap style to use. This can be either - butt (0), round (1), or square (2). - - - - join - - The index of the line join style to use. This can be - either bevel (0), miter (1), or round (2). - - - - thickness - - The thickness of the stroke to draw, in pixels. - - - - r - - The red component of the color to use to stroke the - current path in the specified layer. - - - - g - - The green component of the color to use to stroke the - current path in the specified layer. - - - - b - - The blue component of the color to use to stroke the - current path in the specified layer. - - - - a - - The alpha component of the color to use to stroke the - current path in the specified layer. - - - - -
\ 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 @@ - - -
- cursor - Sets the client's cursor to the image data from the specified - rectangle of a layer, with the specified hotspot. - - cursor - - - - x - - The X coordinate of the cursor's hotspot. - - - - y - - The Y coordinate of the cursor's hotspot. - - - - srclayer - - The index of the layer to copy image data from. - - - - srcx - - The X coordinate of the upper-left corner of the source - rectangle within the source layer. - - - - srcy - - The Y coordinate of the upper-left corner of the source - rectangle within the source layer. - - - - srcwidth - - The width of the source rectangle within the source - layer. - - - - srcheight - - The height of the source rectangle within the source - layer. - - - -
\ 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 @@ - - -
- curve - - curve - - Adds the specified cubic bezier curve subpath. - - - layer - - The layer which should have the specified curve subpath - added. - - - - cp1x - - The X coordinate of the first control point of the - curve. - - - - cp1y - - The Y coordinate of the first control point of the - curve. - - - - cp2x - - The X coordinate of the second control point of the - curve. - - - - cp2y - - The Y coordinate of the second control point of the - curve. - - - - x - - The X coordinate of the endpoint of the curve. - - - - y - - The Y coordinate of the endpoint of the curve. - - - -
\ 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 @@ - - -
- dispose - - - dispose - - Removes the specified layer. The specified layer will be recreated as a - new layer if it is referenced again. - - - layer - - The layer to remove. - - - - -
\ 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 @@ - - -
- distort - - - distort - - 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 - - - layer - - The layer to distort. - - - - a - - The matrix value in row 1, column 1. - - - - b - - The matrix value in row 2, column 1. - - - - c - - The matrix value in row 1, column 2. - - - - d - - The matrix value in row 2, column 2. - - - - e - - The matrix value in row 1, column 3. - - - - f - - The matrix value in row 2, column 3. - - - - -
\ 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 @@ - - -
- identity - - - identity - - Resets the transform matrix of the specified layer to the identity - matrix. - - - layer - - The layer whose transform matrix should be reset. - - - - -
\ 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 @@ - - -
- lfill - - - lfill - - 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. - - - mask - - The channel mask to apply when filling the current path in - the specified layer. - - - - layer - - The layer whose path should be filled. - - - - srclayer - - The layer to use as the pattern. - - - - -
\ 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 @@ - - -
- line - - - line - - Adds the specified line subpath. - - - layer - - The layer which should have the specified line subpath - added. - - - - x - - The X coordinate of the endpoint of the line. - - - - y - - The Y coordinate of the endpoint of the line. - - - - -
\ 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 @@ - - -
- lstroke - - - lstroke - - 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. - - - mask - - The channel mask to apply when filling the current path in - the specified layer. - - - - layer - - The layer whose path should be filled. - - - - cap - - The index of the line cap style to use. This can be either - butt (0), round (1), or square (2). - - - - join - - The index of the line join style to use. This can be - either bevel (0), miter (1), or round (2). - - - - thickness - - The thickness of the stroke to draw, in pixels. - - - - srclayer - - The layer to use as the pattern. - - - - -
\ 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 @@ - - -
- move - - - move - - 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. - - - layer - - The layer to move. - - - - parent - - The layer that should be the parent of the given - layer. - - - - x - - The X coordinate to move the layer to. - - - - y - - The Y coordinate to move the layer to. - - - - z - - The relative Z-ordering of this layer. Layers with larger - values will appear above layers with smaller values. - - - - -
\ 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 @@ - - -
- pop - - - pop - - Restores the previous state of the specified layer from the stack. The - state restored includes the transformation matrix and clipping - path. - - - layer - - The layer whose state should be restored. - - - - -
\ 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 @@ - - -
- push - - - push - - Saves the current state of the specified layer to the stack. The state - saved includes the current transformation matrix and clipping - path. - - - layer - - The layer whose state should be saved. - - - - -
\ 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 @@ - - -
- rect - - - rect - - Adds a rectangular path to the specified layer. - - - mask - - The channel mask to apply when drawing the image - data. - - - - layer - - The destination layer. - - - - x - - The X coordinate of the upper-left corner of the rectangle - to draw. - - - - y - - The Y coordinate of the upper-left corner of the rectangle - to draw. - - - - width - - The width of the rectangle to draw. - - - - height - - The width of the rectangle to draw. - - - - -
\ 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 @@ - - -
- reset - - - reset - - Resets the transformation and clip state of the layer. - - - layer - - The layer whose state should be reset. - - - - -
\ 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 @@ - - -
- set - - - set - - 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). - - - layer - - The layer whose property should be set. - - - - property - - The name of the property to set. - - - - value - - The value to set the given property to. - - - - -
\ 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 @@ - - -
- shade - - - shade - - Sets the opacity of the given layer. - - - layer - - The layer whose opacity should be set. - - - - opacity - - The opacity of the layer, where 0 is completely - transparent, and 255 is completely opaque. - - - - -
\ 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 @@ - - -
- size - - - size - - Sets the size of the specified layer. - - - layer - - The layer to resize. - - - - width - - The new width of the layer - - - - height - - The new height of the layer - - - - -
\ 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 @@ - - -
- start - - - start - - Starts a new subpath at the specified point. - - - layer - - The layer which should start a new subpath. - - - - x - - The X coordinate of the first point of the new - subpath. - - - - y - - The Y coordinate of the first point of the new - subpath. - - - - -
\ 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 @@ - - -
- transfer - - - transfer - - 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 header included with - libguac. - - - srclayer - - The index of the layer to transfer image data from. - - - - srcx - - The X coordinate of the upper-left corner of the source - rectangle within the source layer. - - - - srcy - - The Y coordinate of the upper-left corner of the source - rectangle within the source layer. - - - - srcwidth - - The width of the source rectangle within the source - layer. - - - - srcheight - - The height of the source rectangle within the source - layer. - - - - 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 header included - with libguac. - - - - dstlayer - - The index of the layer to draw the image data to. - - - - dstx - - The X coordinate of the upper-left corner of the - destination within the destination layer. - - - - dsty - - The Y coordinate of the upper-left corner of the - destination within the destination layer. - - - - -
\ 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 @@ - - -
- transform - - - transform - - 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. - - - layer - - The layer to apply the given transformation matrix - to. - - - - a - - The matrix value in row 1, column 1. - - - - b - - The matrix value in row 2, column 1. - - - - c - - The matrix value in row 1, column 2. - - - - d - - The matrix value in row 2, column 2. - - - - e - - The matrix value in row 1, column 3. - - - - f - - The matrix value in row 2, column 3. - - - - -
\ 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 @@ - - -
- - - args - 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. - - -
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 @@ - - -
- body - - body - - 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. - - - object - - The index of the object associated with this stream. - - - - stream - - The index of the stream to allocate. - - - - mimetype - - The mimetype of the data being sent. - - - - name - - The name of the stream associated with the object. - - - -
\ 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 @@ - - -
- filesystem - - filesystem - - 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. - - - object - - The index of the object to allocate. - - - - name - - The name of the filesystem. - - - -
\ 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 @@ - - -
- get - - get - - 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: - - { - "A" : "text/plain", - "B" : "text/plain" -} - - - - object - - The index of the object to request a stream from. - - - - name - - The name of the stream being requested from the given object. - - - -
\ 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 @@ - - -
- put - - put - - 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. - - - object - - The index of the object associated with this stream. - - - - stream - - The index of the stream to allocate. - - - - mimetype - - The mimetype of the data being sent. - - - - name - - The name of the stream within the given object to which data is being - sent. - - - -
\ 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 @@ - - -
- undefine - - undefine - - 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. - - - object - - The index of the object to undefine. - - - -
\ 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 @@ - -
- ack - - ack - - 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 SUCCESS implicitly ends the stream. - - - stream - - The index of the stream the corresponding blob was received on. - - - - message - - A human-readable error message. This typically is not exposed within any user - interface, and mainly helps with debugging. - - - - status - - The Guacamole status code denoting success or failure. - - - -
- 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. - - - - - - - Code - Name - Description - - - - - 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. - - - - - -
-
\ 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 @@ - -
- argv - - argv - - 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. - - - stream - - The index of the stream to allocate. - - - - mimetype - - The mimetype of the connection parameter being sent. In most cases, this will - be "text/plain". - - - - name - - The name of the connection parameter whose value is being sent. - - - -
\ 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 @@ - - -
- audio - - audio - - 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. - - - stream - - The index of the stream to allocate. - - - - mimetype - - The mimetype of the audio data being sent. - - - -
\ 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 @@ - -
- blob - - blob - - 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. - - - stream - - The index of the stream along which the given data should be sent. - - - - data - - The base64-encoded data to send. - - - -
\ 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 @@ - - -
- clipboard - - clipboard - - 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. - - - stream - - The index of the stream to allocate. - - - - mimetype - - The mimetype of the clipboard data being sent. In most cases, this will be - "text/plain". - - - -
\ 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 @@ - -
- end - - end - - 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. - - - stream - - The index of the stream the corresponding blob was received on. - - - -
\ 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 @@ - - -
- file - - file - - 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. - - - stream - - The index of the stream to allocate. - - - - mimetype - - The mimetype of the file being sent. - - - - filename - - The name of the file, as it would be saved on a filesystem. - - - -
\ 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 @@ - - -
- img - - img - - 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. - - - stream - - The index of the stream to allocate. - - - - mimetype - - The mimetype of the image being sent. - - - - mask - - The channel mask to apply when drawing the image data. - - - - layer - - The destination layer. - - - - x - - The X coordinate of the upper-left corner of the destination within the - destination layer. - - - - y - - The Y coordinate of the upper-left corner of the destination within the - destination layer. - - - -
\ 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 @@ - - -
- nest - - nest - - - The nest instruction has been - deprecated. - The nest instruction is no longer necessary, having been replaced - by other streaming instructions (such as blob, ack, and end). Code using the nest - instruction should instead write instructions directly without wrapping those - instructions within nest. - - 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. - - - index - - 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. - - - - data - - The protocol data, containing part of one or more - instructions. - - - -
\ 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 @@ - -
- pipe - - pipe - - 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. - - - stream - - The index of the stream to allocate. - - - - mimetype - - The mimetype of the data being sent along the pipe. - - - - name - - The arbitrary name of the pipe, which may have special meaning to client-side - code. - - - -
\ 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 @@ - - -
- video - - video - - 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. - - - stream - - The index of the stream to allocate. - - - - 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. - - - - mimetype - - The mimetype of the video data being sent. - - - -
\ 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 @@ - - - - Guacamole protocol reference - - Guacamole protocol - - - protocol reference - - - instructions - -
- Drawing instructions - - drawing instructions - - - instructions - drawing - - - server instructions - drawing - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- Streaming instructions - - - - - - - - - - - -
-
- Object instructions - - - - - -
-
- Client handshake instructions - - - - - - - -
-
- Server handshake instructions - -
-
- Client control instructions - - control instructions - - - instructions - control - - - client instructions - control - - - - -
-
- Server control instructions - - server instructions - control - - - - - - - - -
-
- Client events - - events - - - instructions - events - - - client instructions - events - - - - -
-
diff --git a/src/reverse-proxy.rst b/src/reverse-proxy.rst new file mode 100644 index 0000000..d282925 --- /dev/null +++ b/src/reverse-proxy.rst @@ -0,0 +1,441 @@ +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: + +.. container:: informalexample + + :: + + + +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`` `__ +and is configured in the ``conf/server.xml`` file, in the ```` +section: + +.. container:: informalexample + + :: + + + +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: + ++--------------+-------------------------------------------------------+ +| Parameter | Description | +| name | | ++==============+=======================================================+ +| ``remo | The header that is queried to learn the client IP | +| teIpHeader`` | 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. | ++--------------+-------------------------------------------------------+ +| ` | The header that is queried to learn the IP address of | +| `remoteIpPro | the proxy server that forwarded the request. The | +| xiesHeader`` | 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. | ++--------------+-------------------------------------------------------+ +| ``prot | The header that is queried to determine the protocol | +| ocolHeader`` | 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 <#nginx>`__ - the +Apache web server passes it through by default. + +Nginx +----- + +Nginx can be used as a reverse proxy, and supports WebSocket +out-of-the-box `since version +1.3 `__. 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`` `__ +block, declaring the backend hosting Guacamole and explicitly specifying +the "Connection" and "Upgrade" headers mentioned earlier: + +.. container:: informalexample + + :: + + location /guacamole/ { + 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; + } + +Here, 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 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. + +Regardless of the location specified for the proxy, cookies set by +Guacamole will be set using its own absolute path within the backend +(`/guacamole/
`__). If this path differs from that used by +Nginx, the path in the cookie needs to be modified using +``proxy_cookie_path``: + +.. container:: informalexample + + :: + + 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; + proxy_cookie_path /guacamole/ /new-path/; + 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: + +.. container:: informalexample + + :: + + location /guacamole/ { + 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; + client_max_body_size 1g; + access_log off; + } + +.. _apache: + +Apache and mod_proxy +-------------------- + +Apache supports reverse proxy configurations through +`mod_proxy `__. +Apache 2.4.5 and later also support proxying of WebSocket through a +sub-module called +`mod_proxy_wstunnel `__. +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: + +.. container:: informalexample + + :: + + + Order allow,deny + Allow from all + ProxyPass http://HOSTNAME:8080/guacamole/ flushpackets=on + ProxyPassReverse http://HOSTNAME:8080/guacamole/ + + +Here, 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
`__: + +.. container:: informalexample + + :: + + + Order allow,deny + Allow from all + ProxyPass ws://HOSTNAME:8080/guacamole/websocket-tunnel + ProxyPassReverse ws://HOSTNAME:8080/guacamole/websocket-tunnel + + +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 configuration required for Apache +will be slightly different than the examples above due to cookies. + +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. + +Cookies are set using the absolute path of the web application +(`/guacamole/
`__). If this path differs from that used by +Apache, the path in the cookie needs to be modified using the +``ProxyPassReverseCookiePath`` directive: + +.. container:: informalexample + + :: + + + Order allow,deny + Allow from all + ProxyPass http://HOSTNAME:8080/guacamole/ flushpackets=on + ProxyPassReverse http://HOSTNAME:8080/guacamole/ + ProxyPassReverseCookiePath /guacamole/ /new-path/ + + + + Order allow,deny + Allow from all + ProxyPass ws://HOSTNAME:8080/guacamole/websocket-tunnel + ProxyPassReverse ws://HOSTNAME:8080/guacamole/websocket-tunnel + + +This directive is not needed for the WebSocket section, as it is not +applicable. Cookies are only used by Guacamole within the HTTP tunnel. + +.. _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: + +.. container:: informalexample + + :: + + 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.rst b/src/saml-auth.rst new file mode 100644 index 0000000..0ca7c4b --- /dev/null +++ b/src/saml-auth.rst @@ -0,0 +1,135 @@ +.. _saml-auth: + +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 <#configuring-guacamole>`__\ *before +proceeding.* + +To install the SAML authentication extension, you must: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- Copy ``guacamole-auth-saml-1.3.0.jar`` within + ``GUACAMOLE_HOME/extensions``. + +- 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 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 @@ - - - - - - - - - 1 - - - 2 - - - 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 - - - - - - - - - - - - - - - - - - -
- ]]> - - - - -
- ]]> - - - - - - ]]> - - - diff --git a/src/totp-auth.rst b/src/totp-auth.rst new file mode 100644 index 0000000..402750d --- /dev/null +++ b/src/totp-auth.rst @@ -0,0 +1,186 @@ +.. _totp-auth: + +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 <#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 `Database +authentication <#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: + +.. image:: images/totp-auth-factor-1.png + +Only after authentication has succeeded with one of those methods will +Guacamole prompt the user to further verify their identity with an +authentication code: + +.. image:: images/totp-auth-factor-2.png + +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: + +.. image:: images/totp-enroll.png + +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: + +.. image:: images/totp-enroll-detail.png + +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: + +- Create the ``GUACAMOLE_HOME/extensions`` directory, if it does not + already exist. + +- Copy ``guacamole-auth-totp-1.3.0.jar`` within + ``GUACAMOLE_HOME/extensions``. + +- 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.rst b/src/troubleshooting.rst new file mode 100644 index 0000000..151331d --- /dev/null +++ b/src/troubleshooting.rst @@ -0,0 +1,666 @@ +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 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. + +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 +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. + +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: + +.. container:: informalexample + + :: + + 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 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 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() +^^^^^^^^^^^^^^^^^^^^^^^^^ + +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: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 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. + +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 "" +^^^^^^^^^^^^^^^^^^^^^^^^ + +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 +^^^^^^^^^^^^^^^^^^^ + +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 "": 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 ```` 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 ```` 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 ```` 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 +```` 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 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``. + +Specified authentication provider class is not a AuthenticationProvider +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``auth-provider`` property allows you to specify a custom +authentication provider class which will handle all authentication, but +these classes must implement the ``AuthenticationProvider`` interface. +If the class specified does not, this error will be logged. Check that +your authentication provider class implements ``AuthenticationProvider`` +(if you implemented it yourself), and verify that you are specifying the +correct class. + +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 +``lib-directory`` parameter in guacamole.properties. + +Resource /guacamole.properties not found +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Guacamole requires that the ``guacamole.properties`` file is in the +classpath of your servlet container. If it is not, this error will be +logged. Check that ``guacamole.properties`` is in the proper location, +and then restart your servlet container. + +Missing "basic-user-mapping" parameter required for basic login +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you are using the authentication provider included with Guacamole, it +requires the ``basic-user-mapping`` property to be set. If this property +is missing, you will see this error. Add the missing property to +``guacamole.properties``, restart your servlet container, and try again. + +.. _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.rst b/src/using.rst new file mode 100644 index 0000000..bcbb96b --- /dev/null +++ b/src/using.rst @@ -0,0 +1,476 @@ +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. + +.. image:: images/guacamole-home-screen.png + :alt: The Guacamole home screen. The user menu and several recently-used + connections are visible, along with one active connection. + +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 <#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. + +.. image:: images/guacamole-client-interface.png + :alt: Guacamole client interface, with the Guacamole menu open. + +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 +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 +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: + +.. image:: images/guac-menu-disconnect.png + :alt: The user menu within 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. + +.. image:: images/guac-menu-share.png + +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. + +.. image:: images/guac-menu-share-link.png + +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. + +.. image:: images/file-browser.png + :alt: The file browser within the Guacamole menu. + +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. + +.. image:: images/file-transfers.png + :alt: In-progress and completed file transfers. + +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. + +.. image:: images/guacamole-drive.png + :alt: The Guacamole drive within a Windows RDP session. + +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. + +.. image:: images/guacamole-drive-download.png + :alt: The Guacamole drive's "Download" folder. + +.. _guacctl: + +``guacctl`` / ``guacget`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +In addition to traditional drag-and-drop and the file browser, +Guacamole's SSH support can be used with the ``guacctl`` utility. The +``guacctl`` utility is a simple shell script `included with +Guacamole `__ +which allows you to use and configure file transfer directly from the +command line within the SSH session: + +.. container:: informalexample + + :: + + $ 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 +``guacctl`` called ``guacget``. When run as ``guacget``, the utility +behaves as if the ``--download`` option were supplied and initiates a +download for each file specified on the command line. + +.. _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 (+Ctrl+ +Alt+ +Del+ or +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 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. + +.. image:: images/touchscreen.png + +.. _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. + +.. image:: images/touchpad.png + +.. _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. + +.. image:: images/guacamole-preferences.png + :alt: Guacamole preferences screen. + +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/yourown.rst b/src/yourown.rst new file mode 100644 index 0000000..8a3c83a --- /dev/null +++ b/src/yourown.rst @@ -0,0 +1,632 @@ +.. _writing-you-own-guacamole-app: + +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: + +.. container:: informalexample + + :: + + + + 4.0.0 + org.apache.guacamole + guacamole-tutorial + war + 1.3.0 + guacamole-tutorial + + + UTF-8 + + + + +``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. + +.. container:: informalexample + + :: + + + + + + + + index.html + + + + +``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: + +.. container:: informalexample + + :: + + + + + + Guacamole Tutorial + + + +

Hello World

+ + + + +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: + +.. container:: informalexample + + :: + + $ 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 1.6, thus we must add a section to the +``pom.xml`` which describes the source and target Java versions: + +.. container:: informalexample + + :: + + ... + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.6 + 1.6 + + + + + + + + ... + +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: + +.. container:: informalexample + + :: + + ... + + + + + ... + + + + org.apache.maven.plugins + maven-war-plugin + 2.6 + + + + org.apache.guacamole + guacamole-common-js + zip + + + + + + + + + + ... + +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: + +.. container:: informalexample + + :: + + ... + + + + + + javax.servlet + servlet-api + 2.5 + provided + + + + + org.apache.guacamole + guacamole-common + 1.1.0 + compile + + + + + org.apache.guacamole + guacamole-common-js + 1.3.0 + zip + runtime + + + + + ... + +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: + +.. container:: informalexample + + :: + + 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: + +.. container:: informalexample + + :: + + ... + + + + Tunnel servlet. + Tunnel + + org.apache.guacamole.net.example.TutorialGuacamoleTunnelServlet + + + + + Tunnel + /tunnel + + + ... + +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: + +.. container:: informalexample + + :: + + ... + + + + + + +
+ + + + + + ... + +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: + +.. container:: informalexample + + :: + + ... + + + + + ... + +.. _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. +