http://git-wip-us.apache.org/repos/asf/incubator-guacamole-website/blob/2441fd18/doc/0.9.11-incubating/gug/custom-auth.html
----------------------------------------------------------------------
diff --git a/doc/0.9.11-incubating/gug/custom-auth.html 
b/doc/0.9.11-incubating/gug/custom-auth.html
new file mode 100644
index 0000000..f6fc764
--- /dev/null
+++ b/doc/0.9.11-incubating/gug/custom-auth.html
@@ -0,0 +1,383 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";><html 
xmlns="http://www.w3.org/1999/xhtml";><head><meta http-equiv="Content-Type" 
content="text/html; charset=UTF-8" /><title>Chapter 19. Custom 
authentication</title><link rel="stylesheet" type="text/css" href="gug.css" 
/><meta name="generator" content="DocBook XSL-NS Stylesheets V1.78.1" /><link 
rel="home" href="index.html" title="Guacamole Manual" /><link rel="up" 
href="developers-guide.html" title="Part II. Developer's Guide" /><link 
rel="prev" href="custom-protocols.html" title="Chapter 18. Adding new 
protocols" /><link rel="next" href="writing-you-own-guacamole-app.html" 
title="Chapter 20. Writing your own Guacamole application" />
+            <meta name="viewport" content="width=device-width, 
initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, 
target-densitydpi=device-dpi"/>
+        </head><body>
+            <!-- CONTENT -->
+
+            <div id="page"><div id="content">
+        <div class="navheader"><table width="100%" summary="Navigation 
header"><tr><th colspan="3" align="center">Chapter 19. Custom 
authentication</th></tr><tr><td width="20%" align="left"><a accesskey="p" 
href="custom-protocols.html">Prev</a> </td><th width="60%" 
align="center">Part II. Developer's Guide</th><td width="20%" align="right"> 
<a accesskey="n" 
href="writing-you-own-guacamole-app.html">Next</a></td></tr></table><hr 
/></div><div xml:lang="en" class="chapter" lang="en"><div 
class="titlepage"><div><div><h2 class="title"><a id="custom-auth"></a>Chapter 
19. Custom authentication</h2></div></div></div><div 
class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span 
class="section"><a href="custom-auth.html#custom-auth-model">Guacamole's 
authentication model</a></span></dt><dt><span class="section"><a 
href="custom-auth.html#custom-auth-skeleton">A Guacamole extension 
skeleton</a></span></dt><dt><span class="section"><a 
href="custom-auth.html#custom-a
 uth-building">Building the extension</a></span></dt><dt><span 
class="section"><a href="custom-auth.html#custom-auth-config">Configuration and 
authentication</a></span></dt><dt><span class="section"><a 
href="custom-auth.html#custom-auth-more-config">Parsing the 
configuration</a></span></dt><dt><span class="section"><a 
href="custom-auth.html#custom-auth-installing">Installing the 
extension</a></span></dt></dl></div><a id="idm140352907630400" 
class="indexterm"></a><p>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.</p><p>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.</p><p>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 <code 
class="filename">guacamole.properties</code>
+        file.</p><p>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.</p><div 
class="section"><div class="titlepage"><div><div><h2 class="title" 
style="clear: both"><a id="custom-auth-model"></a>Guacamole's authentication 
model</h2></div></div></div><p>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.</p><p>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.</p></div><div class="section"><div class="titlepage"><div><div><h2 
class="title" style="clear: both"><a id="custom-auth-skeleton"></a>A Guacamole 
extension skeleton</h2></div></div></div><p>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.</p><p>The bare minimum required for a Guacamole authentication 
extension is a
+                <code class="filename">pom.xml</code> file listing 
guacamole-ext as a dependency, a single
+            .java file implementing our stub of an authentication provider, 
and a
+                <code class="filename">guac-manifest.json</code> file 
describing the extension and pointing
+            to our authentication provider class.</p><p>In our stub, we won't 
actually do any authentication yet; we'll just universally
+            reject all authentication attempts by returning <code 
class="varname">null</code> for any
+            credentials given. You can verify that this is what happens by 
checking the server
+            logs.</p><div class="example"><a id="idm140352907838496"></a><p 
class="title"><strong>Example 19.1. Barebones <code 
class="filename">pom.xml</code> required for a simple authentication
+                extension.</strong></p><div class="example-contents"><pre 
class="programlisting">&lt;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"&gt;
+
+    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
+    &lt;groupId&gt;org.apache.guacamole&lt;/groupId&gt;
+    &lt;artifactId&gt;guacamole-auth-tutorial&lt;/artifactId&gt;
+    &lt;packaging&gt;jar&lt;/packaging&gt;
+    &lt;version&gt;0.9.11-incubating&lt;/version&gt;
+    &lt;name&gt;guacamole-auth-tutorial&lt;/name&gt;
+
+    &lt;properties&gt;
+        
&lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
+    &lt;/properties&gt;
+
+    &lt;build&gt;
+        &lt;plugins&gt;
+
+            &lt;!-- Written for 1.6 --&gt;
+            &lt;plugin&gt;
+                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
+                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
+                &lt;version&gt;3.3&lt;/version&gt;
+                &lt;configuration&gt;
+                    &lt;source&gt;1.6&lt;/source&gt;
+                    &lt;target&gt;1.6&lt;/target&gt;
+                &lt;/configuration&gt;
+            &lt;/plugin&gt;
+
+        &lt;/plugins&gt;
+    &lt;/build&gt;
+
+    &lt;dependencies&gt;
+
+        &lt;!-- Guacamole Extension API --&gt;
+        &lt;dependency&gt;
+            &lt;groupId&gt;org.apache.guacamole&lt;/groupId&gt;
+            &lt;artifactId&gt;guacamole-ext&lt;/artifactId&gt;
+            &lt;version&gt;0.9.11-incubating&lt;/version&gt;
+            &lt;scope&gt;provided&lt;/scope&gt;
+        &lt;/dependency&gt;
+
+    &lt;/dependencies&gt;
+
+&lt;/project&gt;</pre></div></div><br class="example-break" /><p>We won't need 
to update this <code class="filename">pom.xml</code> throughout the rest of the
+            tutorial. Even after adding new files, Maven will just find them 
and compile as
+            necessary.</p><p>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
+                <code 
class="classname">org.apache.guacamole.auth.TutorialAuthenticationProvider</code>.</p><div
 class="example"><a id="idm140352907715616"></a><p 
class="title"><strong>Example 19.2. A skeleton <code 
class="classname">TutorialAuthenticationProvider</code></strong></p><div 
class="example-contents"><pre class="programlisting">package 
org.apache.guacamole.auth;
+
+import java.util.Map;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.simple.SimpleAuthenticationProvider;
+import org.apache.guacamole.net.auth.Credentials;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+
+/**
+ * Authentication provider implementation intended to demonstrate basic use
+ * of Guacamole's extension API. The credentials and connection information for
+ * a single user are stored directly in guacamole.properties.
+ */
+public class TutorialAuthenticationProvider extends 
SimpleAuthenticationProvider {
+
+    @Override
+    public String getIdentifier() {
+        return "tutorial";
+    }
+
+    @Override
+    public Map&lt;String, GuacamoleConfiguration&gt;
+        getAuthorizedConfigurations(Credentials credentials)
+        throws GuacamoleException {
+
+        // Do nothing ... yet
+        return null;        
+
+    }
+
+}</pre></div></div><br class="example-break" /><p>To conform with Maven, this 
skeleton file must be placed within
+                <code 
class="filename">src/main/java/org/apache/guacamole/auth</code> as
+                <code 
class="filename">TutorialAuthenticationProvider.java</code>.</p><p>Notice how 
simple the authentication provider is. The
+                <code class="classname">SimpleAuthenticationProvider</code> 
base class simplifies the
+                <code class="classname">AuthenticationProvider</code> 
interface, requiring nothing more than
+            a unique identifier (we will use "tutorial") and a single
+                <code class="methodname">getAuthorizedConfigurations()</code> 
implementation, which must
+            return a <code class="classname">Map</code> of <code 
class="classname">GuacamoleConfiguration</code>
+            each associated with some arbitrary unique ID. This unique ID will 
be presented to the
+            user in the connection list after they log in.</p><p>For now, 
<code class="methodname">getAuthorizedConfigurations()</code> will just return
+                <code class="varname">null</code>. 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 <code class="varname">null</code>, 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.</p><p>The only remaining 
piece for the overall skeleton to be complete is a
+                <code class="filename">guac-manifest.json</code> file. <span 
class="emphasis"><em>This file is absolutely
+                required for all Guacamole extensions.</em></span> The
+                <code class="filename">guac-manifest.json</code> format is 
described in more detail in <a class="xref" href="guacamole-ext.html" 
title="Chapter 17. guacamole-ext">Chapter 17, <em>guacamole-ext</em></a>. 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.</p><p>The Guacamole extension format requires that <code 
class="filename">guac-manifest.json</code>
+            be placed in the root directory of the extension <code 
class="filename">.jar</code> file. To
+            accomplish this with Maven, we place it within the
+                <code class="filename">src/main/resources</code> directory. 
Maven will automatically pick it
+            up during the build and include it within the <code 
class="filename">.jar</code>.</p><div class="example"><a 
id="idm140352907746544"></a><p class="title"><strong>Example 19.3. The 
required <code class="filename">guac-manifest.json</code></strong></p><div 
class="example-contents"><pre class="programlisting">{
+
+    "guacamoleVersion" : "0.9.11-incubating",
+
+    "name"      : "Tutorial Authentication Extension",
+    "namespace" : "guac-auth-tutorial",
+
+    "authProviders" : [
+        "org.apache.guacamole.auth.TutorialAuthenticationProvider"
+    ]
+
+}</pre></div></div><br class="example-break" /></div><div class="section"><div 
class="titlepage"><div><div><h2 class="title" style="clear: both"><a 
id="custom-auth-building"></a>Building the 
extension</h2></div></div></div><p>Once all three of the above files are in 
place, the extension will build, and can even
+            be installed within Guacamole (see <a class="xref" 
href="custom-auth.html#custom-auth-installing" title="Installing the 
extension">the section called “Installing the extension”</a> 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:</p><div class="informalexample"><pre class="screen"><code 
class="prompt">$</code> mvn package
+<code class="computeroutput">[INFO] Scanning for projects...
+[INFO] ------------------------------------------------------------------------
+[INFO] Building guacamole-auth-tutorial 0.9.11-incubating
+[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] 
------------------------------------------------------------------------</code>
+<code class="prompt">$</code></pre></div><p>Assuming you see the "<code 
class="computeroutput">BUILD SUCCESS</code>" message when you
+            build the extension, there will be a new file,
+                <code 
class="filename">target/guacamole-auth-tutorial-0.9.11-incubating.jar</code>, 
which can be
+            installed within Guacamole and tested. If you changed the name or 
version of the project
+            in the <code class="filename">pom.xml</code> file, the name of 
this new <code class="filename">.jar</code>
+            file will be different, but it can still be found within
+            <code class="filename">target/</code>.</p></div><div 
class="section"><div class="titlepage"><div><div><h2 class="title" 
style="clear: both"><a id="custom-auth-config"></a>Configuration and 
authentication</h2></div></div></div><p>Once we receive credentials, we need to 
validate those credentials against the
+            associated properties in <code 
class="filename">guacamole.properties</code> (our source of
+            authentication information for the sake of this 
tutorial).</p><p>We will define four properties:</p><div 
class="variablelist"><dl class="variablelist"><dt><span class="term"><span 
class="property">tutorial-user</span></span></dt><dd><p>The name of the only 
user we accept.</p></dd><dt><span class="term"><span 
class="property">tutorial-password</span></span></dt><dd><p>The password we 
require for the user specified to be
+                            authenticated.</p></dd><dt><span 
class="term"><span 
class="property">tutorial-protocol</span></span></dt><dd><p>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.</p></dd><dt><span class="term"><span 
class="property">tutorial-parameters</span></span></dt><dd><p>A comma-delimited 
list of
+                                    <code class="code"><em 
class="replaceable"><code>name</code></em>=<em 
class="replaceable"><code>value</code></em></code>
+                            pairs. For the sake of simplicity, we'll assume 
there will never be any
+                            commas in the values.</p></dd></dl></div><p>If the 
username and password match what is stored in the file, we read the
+            configuration information, store it in a <code 
class="classname">GuacamoleConfiguration</code>,
+            and return the configuration within a set, telling Guacamole that 
this user is
+            authorized but only to access the configurations 
returned.</p><p>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.</p><div class="example"><a 
id="idm140352907698128"></a><p class="title"><strong>Example 19.4. <code 
class="filename">TutorialProperties.java</code>, a class containing property
+                definitions</strong></p><div class="example-contents"><pre 
class="programlisting">package org.apache.guacamole.auth;
+
+import org.apache.guacamole.properties.StringGuacamoleProperty;
+
+/**
+ * Utility class containing all properties used by the custom authentication
+ * tutorial. The properties defined here must be specified within
+ * guacamole.properties to configure the tutorial authentication provider.
+ */
+public class TutorialGuacamoleProperties {
+
+    /**
+     * This class should not be instantiated.
+     */
+    private TutorialGuacamoleProperties() {}
+
+    /**
+     * The only user to allow.
+     */
+    public static final StringGuacamoleProperty TUTORIAL_USER = 
+        new StringGuacamoleProperty() {
+
+        @Override
+        public String getName() { return "tutorial-user"; }
+
+    };
+
+    /**
+     * The password required for the specified user.
+     */
+    public static final StringGuacamoleProperty TUTORIAL_PASSWORD = 
+        new StringGuacamoleProperty() {
+
+        @Override
+        public String getName() { return "tutorial-password"; }
+
+    };
+
+
+    /**
+     * The protocol to use when connecting.
+     */
+    public static final StringGuacamoleProperty TUTORIAL_PROTOCOL = 
+        new StringGuacamoleProperty() {
+
+        @Override
+        public String getName() { return "tutorial-protocol"; }
+
+    };
+
+
+    /**
+     * All parameters associated with the connection, as a comma-delimited
+     * list of name="value" 
+     */
+    public static final StringGuacamoleProperty TUTORIAL_PARAMETERS = 
+        new StringGuacamoleProperty() {
+
+        @Override
+        public String getName() { return "tutorial-parameters"; }
+
+    };
+
+}</pre></div></div><br class="example-break" /><p>Normally, we would define a 
new type of <code class="classname">GuacamoleProperty</code> to
+            handle the parsing of the parameters required by <code 
class="varname">TUTORIAL_PARAMETERS</code>,
+            but for the sake of simplicity, parsing of this parameter will be 
embedded in the
+            authentication function later.</p><p>You will need to modify your 
existing <code class="filename">guacamole.properties</code> file,
+            adding each of the above properties to describe one of your 
available
+            connections.</p><div class="example"><a 
id="idm140352907345456"></a><p class="title"><strong>Example 19.5. Properties 
describing a user and connection, as required by this tutorial</strong></p><div 
class="example-contents"><pre class="programlisting"># Username and password
+tutorial-user:     <em class="replaceable"><code>tutorial</code></em>
+tutorial-password: <em class="replaceable"><code>password</code></em>
+
+# Connection information
+tutorial-protocol:   <em class="replaceable"><code>vnc</code></em>
+tutorial-parameters: <em class="replaceable"><code>hostname=localhost, 
port=5900</code></em></pre></div></div><br class="example-break" /><p>Once 
these properties and their accessor class are in place, it's simple enough to
+            read the properties within <code 
class="methodname">getAuthorizedConfigurations()</code> and
+            authenticate the user based on their username and 
password.</p><div class="example"><a id="idm140352907341248"></a><p 
class="title"><strong>Example 19.6. Checking the credentials against the 
properties</strong></p><div class="example-contents"><pre 
class="programlisting">@Override
+public Map&lt;String, GuacamoleConfiguration&gt;
+    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&lt;String, GuacamoleConfiguration&gt;();
+
+}</pre></div></div><br class="example-break" /><p>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
+                <code class="filename">guacamole.properties</code> file after 
the user has been
+            authenticated, and return that configuration to the web 
application.</p></div><div class="section"><div class="titlepage"><div><div><h2 
class="title" style="clear: both"><a id="custom-auth-more-config"></a>Parsing 
the configuration</h2></div></div></div><p>The only remaining task before we 
have a fully-functioning authentication provider is
+            to actually parse the configuration from the <code 
class="filename">guacamole.properties</code>
+            file.</p><div class="example"><a id="idm140352907335456"></a><p 
class="title"><strong>Example 19.7. Parsing and returning a <code 
class="classname">GuacamoleConfiguration</code></strong></p><div 
class="example-contents"><pre class="programlisting">@Override
+public Map&lt;String, GuacamoleConfiguration&gt;
+    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&lt;String, GuacamoleConfiguration&gt; configs = 
+        new HashMap&lt;String, GuacamoleConfiguration&gt;();
+
+    // 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;
+
+}</pre></div></div><br class="example-break" /><p>The extension is now 
complete and can be built as described earlier in <a class="xref" 
href="custom-auth.html#custom-auth-building" title="Building the extension">the 
section called “Building the extension”</a>.</p></div><div 
class="section"><div class="titlepage"><div><div><h2 class="title" 
style="clear: both"><a id="custom-auth-installing"></a>Installing the 
extension</h2></div></div></div><p>Guacamole extensions are self-contained 
<code class="filename">.jar</code> files which are
+            installed by being placed within <code 
class="filename">GUACAMOLE_HOME/extensions</code>, and
+            this extension is no different. As described in <a class="xref" 
href="configuring-guacamole.html" title="Chapter 5. Configuring 
Guacamole">Chapter 5, <em>Configuring Guacamole</em></a>,
+                <code class="varname">GUACAMOLE_HOME</code> is a placeholder 
used to refer to the directory
+            that Guacamole uses to locate its configuration files and 
extensions. Typically, this
+            will be the <code class="filename">.guacamole</code> directory 
within the home directory of the
+            user running Tomcat.</p><p>To install your extension, ensure that 
the required properties have been added to your
+                <code class="filename">guacamole.properties</code>, copy the
+                <code 
class="filename">target/guacamole-auth-tutorial-0.9.11-incubating.jar</code> 
file into
+                <code class="filename">GUACAMOLE_HOME/extensions</code> and 
restart Tomcat. Guacamole will
+            automatically load your extension, logging an informative message 
that it has done
+            so:</p><div class="informalexample"><pre class="screen">Extension 
"Tutorial Authentication Extension" loaded.</pre></div></div></div><div 
class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td 
width="40%" align="left"><a accesskey="p" 
href="custom-protocols.html">Prev</a> </td><td width="20%" align="center"><a 
accesskey="u" href="developers-guide.html">Up</a></td><td width="40%" 
align="right"> <a accesskey="n" 
href="writing-you-own-guacamole-app.html">Next</a></td></tr><tr><td width="40%" 
align="left" valign="top">Chapter 18. Adding new protocols </td><td 
width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td 
width="40%" align="right" valign="top"> Chapter 20. Writing your own 
Guacamole application</td></tr></table></div>
+
+            </div></div>
+        <!-- Google Analytics -->
+        <script type="text/javascript">
+          
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+          (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new 
Date();a=s.createElement(o),
+          
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+          
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+          ga('create', 'UA-75289145-1', 'auto');
+          ga('send', 'pageview');
+        </script>
+        </body></html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-website/blob/2441fd18/doc/0.9.11-incubating/gug/custom-protocols.html
----------------------------------------------------------------------
diff --git a/doc/0.9.11-incubating/gug/custom-protocols.html 
b/doc/0.9.11-incubating/gug/custom-protocols.html
new file mode 100644
index 0000000..7a5a219
--- /dev/null
+++ b/doc/0.9.11-incubating/gug/custom-protocols.html
@@ -0,0 +1,654 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";><html 
xmlns="http://www.w3.org/1999/xhtml";><head><meta http-equiv="Content-Type" 
content="text/html; charset=UTF-8" /><title>Chapter 18. Adding new 
protocols</title><link rel="stylesheet" type="text/css" href="gug.css" /><meta 
name="generator" content="DocBook XSL-NS Stylesheets V1.78.1" /><link 
rel="home" href="index.html" title="Guacamole Manual" /><link rel="up" 
href="developers-guide.html" title="Part II. Developer's Guide" /><link 
rel="prev" href="guacamole-ext.html" title="Chapter 17. guacamole-ext" 
/><link rel="next" href="custom-auth.html" title="Chapter 19. Custom 
authentication" />
+            <meta name="viewport" content="width=device-width, 
initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, 
target-densitydpi=device-dpi"/>
+        </head><body>
+            <!-- CONTENT -->
+
+            <div id="page"><div id="content">
+        <div class="navheader"><table width="100%" summary="Navigation 
header"><tr><th colspan="3" align="center">Chapter 18. Adding new 
protocols</th></tr><tr><td width="20%" align="left"><a accesskey="p" 
href="guacamole-ext.html">Prev</a> </td><th width="60%" align="center">Part 
II. Developer's Guide</th><td width="20%" align="right"> <a accesskey="n" 
href="custom-auth.html">Next</a></td></tr></table><hr /></div><div 
xml:lang="en" class="chapter" lang="en"><div class="titlepage"><div><div><h2 
class="title"><a id="custom-protocols"></a>Chapter 18. Adding new 
protocols</h2></div></div></div><div class="toc"><p><strong>Table of 
Contents</strong></p><dl class="toc"><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-skeleton">Minimal skeleton 
client</a></span></dt><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-display-init">Initializing the 
remote display</a></span></dt><dt><span class="section"><a 
href="custom-protocols.h
 tml#libguac-client-ball-layer">Adding the ball</a></span></dt><dt><span 
class="section"><a 
href="custom-protocols.html#libguac-client-ball-bounce">Making the ball 
bounce</a></span></dt><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-pretty">A prettier 
ball</a></span></dt><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-time">Handling the passage of 
time</a></span></dt></dl></div><a id="idm140352911490960" 
class="indexterm"></a><p>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.</p><p>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.</p><p>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.</p><p>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.</p><p>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:</p><div class="variablelist"><dl class="variablelist"><dt><span 
class="term"><code class="filename">configure.ac</code></span></dt><dd><p>Used 
by GNU Automake to generate the <code class="filename">configure</code> script
+                    which ultimately serves to generate the <code 
class="filename">Makefile</code> which
+                        <span class="command"><strong>make</strong></span> 
will use when building.</p></dd><dt><span class="term"><code 
class="filename">Makefile.am</code></span></dt><dd><p>Used by GNU Automake and 
the <code class="filename">configure</code> script to generate
+                    the <code class="filename">Makefile</code> which <span 
class="command"><strong>make</strong></span> will use when
+                    building.</p></dd><dt><span class="term"><code 
class="filename">src/ball.c</code></span></dt><dd><p>The main body of code 
defining the bouncing ball "client".</p></dd><dt><span class="term"><code 
class="filename">src/ball.h</code></span></dt><dd><p>A header file defining the 
structure representing the state of the bouncing
+                    ball (once it becomes necessary to do 
so).</p></dd></dl></div><p>All source files will be within the <code 
class="filename">src</code> subdirectory, as is common
+        with C projects, with build files being at the root level directory. 
The main
+            <code class="filename">src/ball.c</code> and the build-related 
<code class="filename">configure.ac</code>
+        and <code class="filename">Makefile.am</code> files will be created 
first, with each successive step
+        building upon those files iteratively, with <code 
class="filename">src/ball.h</code> being added when
+        it becomes necessary. After each step, you can build/rebuild the 
plugin by running
+            <span class="command"><strong>make</strong></span>, and then 
install it (such that guacd can find the plugin) by
+        running <span class="command"><strong>make install</strong></span> and 
<span class="command"><strong>ldconfig</strong></span> as root:</p><div 
class="informalexample"><pre class="screen"><code class="prompt">$</code> 
<strong class="userinput"><code>make</code></strong>
+<code class="computeroutput">  CC       src/ball.lo
+  CCLD     libguac-client-ball.la</code>
+<code class="prompt">#</code> <strong class="userinput"><code>make 
install</code></strong>
+<code class="computeroutput">make[1]: Entering directory 
'/home/user/libguac-client-ball'
+ /usr/bin/mkdir -p '/usr/local/lib'
+ /bin/sh ./libtool   --mode=install /usr/bin/install -c   
libguac-client-ball.la '/usr/local/lib'
+...
+----------------------------------------------------------------------
+Libraries have been installed in:
+   /usr/local/lib
+
+If you ever happen to want to link against installed libraries
+in a given directory, LIBDIR, you must either use libtool, and
+specify the full pathname of the library, or use the '-LLIBDIR'
+flag during linking and do at least one of the following:
+   - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable
+     during execution
+   - add LIBDIR to the 'LD_RUN_PATH' environment variable
+     during linking
+   - use the '-Wl,-rpath -Wl,LIBDIR' linker flag
+   - have your system administrator add LIBDIR to '/etc/ld.so.conf'
+
+See any operating system documentation about shared libraries for
+more information, such as the ld(1) and ld.so(8) manual pages.
+----------------------------------------------------------------------
+make[1]: Nothing to be done for 'install-data-am'.
+make[1]: Leaving directory '/home/user/libguac-client-ball'</code>
+<code class="prompt">#</code> <strong 
class="userinput"><code>ldconfig</code></strong></pre></div><p>Prior to the 
first time <span class="command"><strong>make</strong></span> is invoked, you 
will need to run the
+            <code class="filename">configure</code> script, which will first 
need to be generated using
+            <span class="command"><strong>autoreconf</strong></span>:</p><div 
class="informalexample"><pre class="screen"><code class="prompt">$</code> 
<strong class="userinput"><code>autoreconf -fi</code></strong>
+<code class="computeroutput">libtoolize: putting auxiliary files in '.'.
+libtoolize: copying file './ltmain.sh'
+libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
+libtoolize: copying file 'm4/libtool.m4'
+libtoolize: copying file 'm4/ltoptions.m4'
+libtoolize: copying file 'm4/ltsugar.m4'
+libtoolize: copying file 'm4/ltversion.m4'
+libtoolize: copying file 'm4/lt~obsolete.m4'
+configure.ac:10: installing './compile'
+configure.ac:4: installing './missing'
+Makefile.am: installing './depcomp'</code>
+<code class="prompt">$</code> <strong 
class="userinput"><code>./configure</code></strong>
+<code class="computeroutput">checking for a BSD-compatible install... 
/usr/bin/install -c
+checking whether build environment is sane... yes
+...
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: executing depfiles commands
+config.status: executing libtool commands</code>
+<code class="prompt">$</code></pre></div><p>This process is almost identical 
to that of building guacamole-server from git, as
+        documented in <a class="xref" 
href="installing-guacamole.html#building-guacamole-server" title="Building 
guacamole-server">the section called “Building <span 
class="package">guacamole-server</span>”</a>.</p><div class="important"><h3 
class="title">Important</h3><p>The libguac library which is part of 
guacamole-server is a required dependency of this
+            project. <span class="emphasis"><em>You must first install 
libguac, guacd, etc. by <a class="link" 
href="installing-guacamole.html#building-guacamole-server" title="Building 
guacamole-server">building and installing guacamole-server</a>.</em></span> If 
guacamole-server
+            has not been installed, and libguac is thus not present, the
+                <code class="filename">configure</code> script will fail with 
an error indicating that it
+            could not find libguac:</p><div class="informalexample"><pre 
class="screen"><code class="prompt">$</code> <strong 
class="userinput"><code>./configure</code></strong>
+<code class="computeroutput">checking for a BSD-compatible install... 
/usr/bin/install -c
+checking whether build environment is sane... yes
+...
+checking for guac_client_stream_png in -lguac... no
+configure: error: "libguac is required for communication via "
+                   "the Guacamole protocol"</code>
+<code class="prompt">$</code></pre></div><p>You will need to install 
guacamole-server and then rerun
+                <code class="filename">configure</code>.</p></div><div 
class="section"><div class="titlepage"><div><div><h2 class="title" 
style="clear: both"><a id="libguac-client-ball-skeleton"></a>Minimal skeleton 
client</h2></div></div></div><p>Very little needs too be done to implement the 
most basic client plugin possible. We
+            begin with <code class="filename">src/ball.c</code>, containing 
the absolute minimum required for
+            a client plugin:</p><div class="informalexample"><a 
id="ball-01-ball_client.c"></a><pre xml:lang="en" class="programlisting" 
lang="en">#include &lt;guacamole/client.h&gt;
+
+#include &lt;stdlib.h&gt;
+
+/* Client plugin arguments (empty) */
+const char* TUTORIAL_ARGS[] = { NULL };
+
+int guac_client_init(guac_client* client) {
+
+    /* This example does not implement any arguments */
+    client-&gt;args = TUTORIAL_ARGS;
+
+    return 0;
+
+}</pre></div><p>Notice the structure of this file. There is exactly one 
function,
+                <code class="methodname">guac_client_init</code>, which is the 
entry
+            point for all Guacamole client plugins. Just as a typical C program
+            has a <code class="methodname">main</code> function which is 
executed when
+            the program is run, a Guacamole client plugin has
+                <code class="methodname">guac_client_init</code> which is 
called when
+            guacd loads the plugin when a new connection is made and your
+            protocol is selected.</p><p><code 
class="methodname">guac_client_init</code> receives a single
+                <code class="classname">guac_client</code> 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 <a class="xref" 
href="configuring-guacamole.html#connection-configuration" title="Configuring 
connections">the section called “Configuring connections”</a>).</p><p>The 
<code class="classname">guac_client</code> instance given to
+                <code class="methodname">guac_client_init</code> 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.</p><p>For this project to build with GNU Automake, we a <code 
class="filename">configure.ac</code>
+            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:</p><div 
class="informalexample"><a id="ball-01-configure.in"></a><pre xml:lang="en" 
class="programlisting" lang="en"># Project information
+AC_PREREQ([2.61])
+AC_INIT([libguac-client-ball], [0.1.0])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
+AM_SILENT_RULES([yes])
+
+AC_CONFIG_MACRO_DIRS([m4])
+
+# Check for required build tools
+AC_PROG_CC
+AC_PROG_CC_C99
+AC_PROG_LIBTOOL
+
+# Check for libguac
+AC_CHECK_LIB([guac], [guac_client_stream_png],,
+      AC_MSG_ERROR("libguac is required for communication via "
+                   "the Guacamole protocol"))
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT</pre></div><p>We also need a <code 
class="filename">Makefile.am</code>, describing which files should be
+            built and how when building
+            libguac-client-ball:<a id="ball-01-Makefile.am"></a></p><pre 
xml:lang="en" class="programlisting" lang="en">AUTOMAKE_OPTIONS = foreign
+
+ACLOCAL_AMFLAGS = -I m4
+AM_CFLAGS = -Werror -Wall -pedantic
+
+lib_LTLIBRARIES = libguac-client-ball.la
+
+# All source files of libguac-client-ball
+libguac_client_ball_la_SOURCES = src/ball.c
+
+# libtool versioning information
+libguac_client_ball_la_LDFLAGS = -version-info 0:0:0</pre><p>The GNU Automake 
files will remain largely unchanged throughout
+            the rest of the tutorial. </p><p>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.</p></div><div class="section"><div 
class="titlepage"><div><div><h2 class="title" style="clear: both"><a 
id="libguac-client-ball-display-init"></a>Initializing the remote 
display</h2></div></div></div><p>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.</p><p>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 <span 
class="emphasis"><em>can</em></span> be chosen
+            based on the size of the user's browser window (which is provided 
by the user during the
+                <a class="link" 
href="guacamole-protocol.html#guacamole-protocol-handshake" title="Handshake 
phase">Guacamole protocol handshake</a>), or even
+            updated when the window size changes (provided by the user via <a 
class="link" href="protocol-reference.html#size-event-instruction" 
title="size">"size"
+                instructions</a>), we won't be doing that here for the 
simplicity's sake:</p><div class="informalexample"><a 
id="ball-02-ball_client.c"></a><pre xml:lang="en" class="programlisting" 
lang="en">#include &lt;guacamole/client.h&gt;
+<span class="emphasis"><em>#include &lt;guacamole/protocol.h&gt;
+#include &lt;guacamole/socket.h&gt;
+#include &lt;guacamole/user.h&gt;</em></span>
+
+#include &lt;stdlib.h&gt;
+
+...
+
+<span class="emphasis"><em>int ball_join_handler(guac_user* user, int argc, 
char** argv) {
+
+    /* Get client associated with user */
+    guac_client* client = user-&gt;client;
+
+    /* Get user-specific socket */
+    guac_socket* socket = user-&gt;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-&gt;last_sent_timestamp);
+
+    /* Flush buffer */
+    guac_socket_flush(socket);
+
+    /* User successfully initialized */
+    return 0;
+
+}</em></span>
+
+int guac_client_init(guac_client* client) {
+
+    /* This example does not implement any arguments */
+    client-&gt;args = TUTORIAL_ARGS;
+<span class="emphasis"><em>
+    /* Client-level handlers */
+    client-&gt;join_handler = ball_join_handler;
+</em></span>
+    return 0;
+
+}</pre></div><p>The most important thing to notice here is the new
+                <code class="function">ball_join_handler()</code> function. As 
it is assigned to
+                <span class="property">join_handler</span> of the <code 
class="classname">guac_client</code> given to
+                <code class="function">guac_client_init</code>, 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
+                <code class="classname">guac_user</code>, taking into account 
any arguments received from
+            the user during the connection handshake (exposed through <code 
class="varname">argc</code> and
+                <code class="varname">argv</code> 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:</p><div 
class="orderedlist"><ol class="orderedlist" type="1"><li 
class="listitem"><p>Send a <a class="link" 
href="protocol-reference.html#size-instruction" title="size">"size" 
instruction</a>, initializing the
+                    display size to 1024x768.</p></li><li 
class="listitem"><p>Draw a 1024x768 gray rectangle over the display using the 
<a class="link" href="protocol-reference.html#rect-instruction" 
title="rect">"rect"</a> and <a class="link" 
href="protocol-reference.html#cfill-instruction" title="cfill">"cfill"</a> 
instructions.</p></li><li class="listitem"><p>Send a <a class="link" 
href="protocol-reference.html#server-sync-instruction" title="sync">"sync" 
instruction</a>, informing the
+                    remote display that a frame has been 
completed.</p></li><li class="listitem"><p>Flush the socket, ensuring that all 
data written to the socket thus far is
+                    immediately sent to the user.</p></li></ol></div><p>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.</p></div><div 
class="section"><div class="titlepage"><div><div><h2 class="title" 
style="clear: both"><a id="libguac-client-ball-layer"></a>Adding the 
ball</h2></div></div></div><p>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.</p><p>The remote display has a single root layer, <code 
class="varname">GUAC_DEFAULT_LAYER</code>, 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.</p><p>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,
+                <code class="filename">src/ball.h</code>, to define 
this:</p><div class="informalexample"><pre xml:lang="en" class="programlisting" 
lang="en">#ifndef BALL_H
+#define BALL_H
+
+#include &lt;guacamole/layer.h&gt;
+
+typedef struct ball_client_data {
+
+    guac_layer* ball;
+
+} ball_client_data;
+
+#endif</pre></div><p>To make the build system aware of the existence of the new
+                <code class="filename">src/ball.h</code> header file, <code 
class="filename">Makefile.am</code> must
+            be updated as well:</p><div class="informalexample"><pre 
xml:lang="en" class="programlisting" lang="en">...
+
+# All source files of libguac-client-ball
+<span class="emphasis"><em>noinst_HEADERS = src/ball.h</em></span>
+libguac_client_ball_la_SOURCES = src/ball.c
+
+...</pre></div><p>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 <code 
class="function">guac_client_init</code>), 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:</p><div 
class="informalexample"><a id="ball-03-ball_client.c"></a><pre xml:lang="en" 
class="programlisting" lang="en"><span class="emphasis"><em>#include 
"ball.h"</em></span>
+
+#include &lt;guacamole/client.h&gt;
+<span class="emphasis"><em>#include &lt;guacamole/layer.h&gt;</em></span>
+#include &lt;guacamole/protocol.h&gt;
+#include &lt;guacamole/socket.h&gt;
+#include &lt;guacamole/user.h&gt;
+
+#include &lt;stdlib.h&gt;
+
+...
+
+int ball_join_handler(guac_user* user, int argc, char** argv) {
+
+    /* Get client associated with user */
+    guac_client* client = user-&gt;client;
+<span class="emphasis"><em>
+    /* Get ball layer from client data */
+    ball_client_data* data = (ball_client_data*) client-&gt;data;
+    guac_layer* ball = data-&gt;ball;
+</em></span>
+    ...
+<span class="emphasis"><em>
+    /* 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);
+</em></span>
+    /* Mark end-of-frame */
+    guac_protocol_send_sync(socket, client-&gt;last_sent_timestamp);
+
+    /* Flush buffer */
+    guac_socket_flush(socket);
+
+    /* User successfully initialized */
+    return 0;
+
+}
+
+<span class="emphasis"><em>int ball_free_handler(guac_client* client) {
+
+    ball_client_data* data = (ball_client_data*) client-&gt;data;
+
+    /* Free client-level ball layer */
+    guac_client_free_layer(client, data-&gt;ball);
+
+    /* Free client-specific data */
+    free(data);
+
+    /* Data successfully freed */
+    return 0;
+
+}</em></span>
+
+int guac_client_init(guac_client* client) {
+<span class="emphasis"><em>
+    /* Allocate storage for client-specific data */
+    ball_client_data* data = malloc(sizeof(ball_client_data));
+
+    /* Set up client data and handlers */
+    client-&gt;data = data;
+
+    /* Allocate layer at the client level */
+    data-&gt;ball = guac_client_alloc_layer(client);
+</em></span>
+    ...
+
+    /* Client-level handlers */
+    client-&gt;join_handler = ball_join_handler;
+    <span class="emphasis"><em>client-&gt;free_handler = 
ball_free_handler;</em></span>
+
+    return 0;
+
+}</pre></div><p>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.</p><p>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).</p></div><div class="section"><div 
class="titlepage"><div><div><h2 class="title" style="clear: both"><a 
id="libguac-client-ball-bounce"></a>Making the ball 
bounce</h2></div></div></div><p>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:</p><div 
class="informalexample"><a id="ball-04-ball_client.h"></a><pre xml:lang="en" 
class="programlisting" lang="en">...
+
+#include &lt;guacamole/layer.h&gt;
+
+<span class="emphasis"><em>#include &lt;pthread.h&gt;</em></span>
+
+typedef struct ball_client_data {
+
+    guac_layer* ball;
+<span class="emphasis"><em>
+    int ball_x;
+    int ball_y;
+
+    int ball_velocity_x;
+    int ball_velocity_y;
+
+    pthread_t render_thread;
+</em></span>
+} ball_client_data;
+
+...</pre></div><p>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:</p><div class="informalexample"><pre 
xml:lang="en" class="programlisting" lang="en">#include "ball.h"
+
+#include &lt;guacamole/client.h&gt;
+#include &lt;guacamole/layer.h&gt;
+#include &lt;guacamole/protocol.h&gt;
+#include &lt;guacamole/socket.h&gt;
+#include &lt;guacamole/user.h&gt;
+
+<span class="emphasis"><em>#include &lt;pthread.h&gt;</em></span>
+#include &lt;stdlib.h&gt;
+
+...
+
+<span class="emphasis"><em>void* ball_render_thread(void* arg) {
+
+    /* Get data */
+    guac_client* client = (guac_client*) arg;
+    ball_client_data* data = (ball_client_data*) client-&gt;data;
+
+    /* Update ball position as long as client is running */
+    while (client-&gt;state == GUAC_CLIENT_RUNNING) {
+
+        /* Sleep a bit */
+        usleep(30000);
+
+        /* Update position */
+        data-&gt;ball_x += data-&gt;ball_velocity_x * 30 / 1000;
+        data-&gt;ball_y += data-&gt;ball_velocity_y * 30 / 1000;
+
+        /* Bounce if necessary */
+        if (data-&gt;ball_x &lt; 0) {
+            data-&gt;ball_x = -data-&gt;ball_x;
+            data-&gt;ball_velocity_x = -data-&gt;ball_velocity_x;
+        }
+        else if (data-&gt;ball_x &gt;= 1024 - 128) {
+            data-&gt;ball_x = (2 * (1024 - 128)) - data-&gt;ball_x;
+            data-&gt;ball_velocity_x = -data-&gt;ball_velocity_x;
+        }
+
+        if (data-&gt;ball_y &lt; 0) {
+            data-&gt;ball_y = -data-&gt;ball_y;
+            data-&gt;ball_velocity_y = -data-&gt;ball_velocity_y;
+        }
+        else if (data-&gt;ball_y &gt;= 768 - 128) {
+            data-&gt;ball_y = (2 * (768 - 128)) - data-&gt;ball_y;
+            data-&gt;ball_velocity_y = -data-&gt;ball_velocity_y;
+        }
+
+        guac_protocol_send_move(client-&gt;socket, data-&gt;ball,
+                GUAC_DEFAULT_LAYER, data-&gt;ball_x, data-&gt;ball_y, 0);
+
+        /* End frame and flush socket */
+        guac_client_end_frame(client);
+        guac_socket_flush(client-&gt;socket);
+
+    }
+
+    return NULL;
+
+}</em></span>
+
+...</pre></div><p>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
+                <code class="function">guac_client_end_frame()</code>. This 
function sends a "sync"
+            containing the current timestamp, and updates the properties of the
+                <code class="classname">guac_client</code> with the last-sent 
timestamp (the value that our
+            join handler uses to send <span 
class="emphasis"><em>its</em></span> sync). Note that we don't redraw the
+            whole display with each frame - we simply update the position of 
the ball layer using a
+                <a class="link" 
href="protocol-reference.html#move-instruction" title="move">"move"
+                instruction</a>, and rely on the remote display to handle 
compositing on its
+            own.</p><p>We now need to update <code 
class="methodname">guac_client_init</code> to actually create
+            this thread, initialize the ball state within the structure, and 
store the thread for
+            future cleanup when the client terminates:</p><div 
class="informalexample"><a id="ball-04-ball_client.c"></a><pre xml:lang="en" 
class="programlisting" lang="en">...
+
+int ball_free_handler(guac_client* client) {
+
+    ball_client_data* data = (ball_client_data*) client-&gt;data;
+<span class="emphasis"><em>
+    /* Wait for render thread to terminate */
+    pthread_join(data-&gt;render_thread, NULL);
+</em></span>
+    ...
+
+}
+
+int guac_client_init(guac_client* client) {
+
+    ...
+<span class="emphasis"><em>
+    /* Start ball at upper left */
+    data-&gt;ball_x = 0;
+    data-&gt;ball_y = 0;
+
+    /* Move at a reasonable pace to the lower right */
+    data-&gt;ball_velocity_x = 200; /* pixels per second */
+    data-&gt;ball_velocity_y = 200; /* pixels per second */
+
+    /* Start render thread */
+    pthread_create(&amp;data-&gt;render_thread, NULL, ball_render_thread, 
client);
+</em></span>
+    ...
+
+}</pre></div><p>The thread contains a render loop which continually checks the
+                <span class="property">state</span> property of the <code 
class="classname">guac_client</code>. This
+            property is set to <code 
class="constant">GUAC_CLIENT_RUNNING</code> 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
+                <code class="constant">GUAC_CLIENT_STOPPING</code>. The free 
handler we've written can thus
+            rely on <code class="function">pthread_join()</code> to block 
until the data previously used by
+            the plugin is no longer being used and can safely be 
freed.</p><p>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.</p></div><div class="section"><div 
class="titlepage"><div><div><h2 class="title" style="clear: both"><a 
id="libguac-client-ball-pretty"></a>A prettier 
ball</h2></div></div></div><p>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.</p><p>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:</p><div 
class="informalexample"><a id="ball-05-ball_client.c"></a><pre xml:lang="en" 
class="programlisting" lang="en">int ball_join_handler(guac_user* user, int 
argc, char** argv) {
+
+    ...
+<span class="emphasis"><em>
+    /* 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);
+</em></span>
+
+    /* Prepare a curve which covers the entire layer */
+    guac_protocol_send_rect(socket, GUAC_DEFAULT_LAYER,
+            0, 0, 1024, 768);
+
+     /* Fill curve with <span class="emphasis"><em>texture</em></span> */
+    <span class="emphasis"><em>guac_protocol_send_lfill</em></span>(socket,
+            GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
+            <span class="emphasis"><em>texture</em></span>);
+
+    /* Set up ball layer */
+    guac_protocol_send_size(socket, ball, 128, 128);
+<span class="emphasis"><em>
+    /* Prepare a circular curve */
+    guac_protocol_send_arc(socket, data-&gt;ball,
+            64, 64, 62, 0, 6.28, 0);
+
+    guac_protocol_send_close(socket, data-&gt;ball);
+
+    /* Draw a 4-pixel black border */
+    guac_protocol_send_cstroke(socket,
+            GUAC_COMP_OVER, data-&gt;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-&gt;ball,
+            0x00, 0x80, 0x80, 0x80);
+
+    /* Free texture (no longer needed) */
+    guac_client_free_buffer(client, texture);
+</em></span>
+    /* Mark end-of-frame */
+    guac_protocol_send_sync(socket, client-&gt;last_sent_timestamp);
+
+    ...
+
+}</pre></div><p>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.</p></div><div class="section"><div 
class="titlepage"><div><div><h2 class="title" style="clear: both"><a 
id="libguac-client-ball-time"></a>Handling the passage of 
time</h2></div></div></div><p>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. </p><p>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:</p><div class="informalexample"><pre 
xml:lang="en" class="programlisting" lang="en">#include "ball.h"
+
+#include &lt;guacamole/client.h&gt;
+#include &lt;guacamole/layer.h&gt;
+#include &lt;guacamole/protocol.h&gt;
+#include &lt;guacamole/socket.h&gt;
+<span class="emphasis"><em>#include &lt;guacamole/timestamp.h&gt;</em></span>
+#include &lt;guacamole/user.h&gt;
+
+#include &lt;pthread.h&gt;
+#include &lt;stdlib.h&gt;
+
+...
+
+void* ball_render_thread(void* arg) {
+
+    ...
+<span class="emphasis"><em>
+    /* Init time of last frame to current time */
+    guac_timestamp last_frame = guac_timestamp_current();
+</em></span>
+    /* Update ball position as long as client is running */
+    while (client-&gt;state == CLIENT_RUNNING) {
+<span class="emphasis"><em>
+        /* 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 &gt; 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;
+</em></span>
+        /* Update position */
+        data-&gt;ball_x += data-&gt;ball_velocity_x * <span 
class="emphasis"><em>delta_t</em></span> / 1000;
+        data-&gt;ball_y += data-&gt;ball_velocity_y * <span 
class="emphasis"><em>delta_t</em></span> / 1000;
+
+        ...
+<span class="emphasis"><em>
+        /* Update timestamp */
+        last_frame = current;
+</em></span>
+    }
+
+    ...
+
+}</pre></div><p>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.</p><p>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.</p></div></div><div 
class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td 
width="40%" align="left"><a accesskey="p" href="guacamole-ext.html">Prev</a> 
</td><td width="20%" align="center"><a accesskey="u" 
href="developers-guide.html">Up</a></td><td width="40%" align="right"> <a 
accesskey="n" href="custom-auth.html">Next</a></td></tr><tr><td width="40%" 
align="left" valign="top">Chapter 17. guacamole-ext </td><td width="20%" 
align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" 
align="right" valign="top"> Chapter 19. Custom 
authentication</td></tr></table></div>
+
+            </div></div>
+        <!-- Google Analytics -->
+        <script type="text/javascript">
+          
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+          (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new 
Date();a=s.createElement(o),
+          
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+          
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+          ga('create', 'UA-75289145-1', 'auto');
+          ga('send', 'pageview');
+        </script>
+        </body></html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-website/blob/2441fd18/doc/0.9.11-incubating/gug/developers-guide.html
----------------------------------------------------------------------
diff --git a/doc/0.9.11-incubating/gug/developers-guide.html 
b/doc/0.9.11-incubating/gug/developers-guide.html
new file mode 100644
index 0000000..5bed0ac
--- /dev/null
+++ b/doc/0.9.11-incubating/gug/developers-guide.html
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";><html 
xmlns="http://www.w3.org/1999/xhtml";><head><meta http-equiv="Content-Type" 
content="text/html; charset=UTF-8" /><title>Part II. Developer's 
Guide</title><link rel="stylesheet" type="text/css" href="gug.css" /><meta 
name="generator" content="DocBook XSL-NS Stylesheets V1.78.1" /><link 
rel="home" href="index.html" title="Guacamole Manual" /><link rel="up" 
href="index.html" title="Guacamole Manual" /><link rel="prev" 
href="troubleshooting.html" title="Chapter 12. Troubleshooting" /><link 
rel="next" href="guacamole-protocol.html" title="Chapter 13. The Guacamole 
protocol" />
+            <meta name="viewport" content="width=device-width, 
initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, 
target-densitydpi=device-dpi"/>
+        </head><body>
+            <!-- CONTENT -->
+
+            <div id="page"><div id="content">
+        <div class="navheader"><table width="100%" summary="Navigation 
header"><tr><th colspan="3" align="center">Part II. Developer's 
Guide</th></tr><tr><td width="20%" align="left"><a accesskey="p" 
href="troubleshooting.html">Prev</a> </td><th width="60%" align="center"> 
</th><td width="20%" align="right"> <a accesskey="n" 
href="guacamole-protocol.html">Next</a></td></tr></table><hr /></div><div 
class="part"><div class="titlepage"><div><div><h1 class="title"><a 
id="developers-guide"></a>Part II. Developer's 
Guide</h1></div></div></div><div class="toc"><p><strong>Table of 
Contents</strong></p><dl class="toc"><dt><span class="chapter"><a 
href="guacamole-protocol.html">13. The Guacamole 
protocol</a></span></dt><dd><dl><dt><span class="section"><a 
href="guacamole-protocol.html#guacamole-protocol-design">Design</a></span></dt><dt><span
 class="section"><a 
href="guacamole-protocol.html#guacamole-protocol-handshake">Handshake 
phase</a></span></dt><dt><span class="section"><a href="
 
guacamole-protocol.html#guacamole-protocol-drawing">Drawing</a></span></dt><dt><span
 class="section"><a 
href="guacamole-protocol.html#guacamole-protocol-streaming">Streams and 
objects</a></span></dt><dt><span class="section"><a 
href="guacamole-protocol.html#guacamole-protocol-events">Events</a></span></dt><dt><span
 class="section"><a 
href="guacamole-protocol.html#guacamole-protocol-disconnecting">Disconnecting</a></span></dt></dl></dd><dt><span
 class="chapter"><a href="libguac.html">14. 
libguac</a></span></dt><dd><dl><dt><span class="section"><a 
href="libguac.html#libguac-error-handling">Error 
handling</a></span></dt><dt><span class="section"><a 
href="libguac.html#libguac-client-plugins">Client 
plugins</a></span></dt><dt><span class="section"><a 
href="libguac.html#libguac-layers">Layers and buffers</a></span></dt><dt><span 
class="section"><a 
href="libguac.html#libguac-streams">Streams</a></span></dt><dt><span 
class="section"><a href="libguac.html#libguac-sending-instructions">Sendin
 g instructions</a></span></dt><dt><span class="section"><a 
href="libguac.html#libguac-event-handling">Event 
handling</a></span></dt></dl></dd><dt><span class="chapter"><a 
href="guacamole-common.html">15. <span 
class="package">guacamole-common</span></a></span></dt><dd><dl><dt><span 
class="section"><a href="guacamole-common.html#java-http-tunnel">HTTP 
tunnel</a></span></dt><dt><span class="section"><a 
href="guacamole-common.html#java-protocol-usage">Using the Guacamole 
protocol</a></span></dt></dl></dd><dt><span class="chapter"><a 
href="guacamole-common-js.html">16. 
guacamole-common-js</a></span></dt><dd><dl><dt><span class="section"><a 
href="guacamole-common-js.html#guacamole-client">Guacamole 
client</a></span></dt><dt><span class="section"><a 
href="guacamole-common-js.html#http-tunnel">HTTP 
tunnel</a></span></dt><dt><span class="section"><a 
href="guacamole-common-js.html#input-abstraction">Input 
abstraction</a></span></dt><dt><span class="section"><a 
href="guacamole-common-js.html#
 on-screen-keyboard">On-screen keyboard</a></span></dt></dl></dd><dt><span 
class="chapter"><a href="guacamole-ext.html">17. 
guacamole-ext</a></span></dt><dd><dl><dt><span class="section"><a 
href="guacamole-ext.html#ext-file-format">Guacamole extension 
format</a></span></dt><dt><span class="section"><a 
href="guacamole-ext.html#ext-environment">Accessing the server 
configuration</a></span></dt><dt><span class="section"><a 
href="guacamole-ext.html#ext-auth-providers">Authentication 
providers</a></span></dt><dt><span class="section"><a 
href="guacamole-ext.html#ext-user-context">The <code 
class="classname">UserContext</code></a></span></dt><dt><span 
class="section"><a href="guacamole-ext.html#ext-object-directories"><code 
class="classname">Directory</code> classes</a></span></dt><dt><span 
class="section"><a 
href="guacamole-ext.html#ext-permissions">Permissions</a></span></dt><dt><span 
class="section"><a 
href="guacamole-ext.html#ext-connections">Connections</a></span></dt><dt><span 
class="
 section"><a href="guacamole-ext.html#ext-active-connections">Managing/sharing 
active connections</a></span></dt></dl></dd><dt><span class="chapter"><a 
href="custom-protocols.html">18. Adding new 
protocols</a></span></dt><dd><dl><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-skeleton">Minimal skeleton 
client</a></span></dt><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-display-init">Initializing the 
remote display</a></span></dt><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-layer">Adding the 
ball</a></span></dt><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-bounce">Making the ball 
bounce</a></span></dt><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-pretty">A prettier 
ball</a></span></dt><dt><span class="section"><a 
href="custom-protocols.html#libguac-client-ball-time">Handling the passage of 
time</a></span></dt></dl></dd><dt><span clas
 s="chapter"><a href="custom-auth.html">19. Custom 
authentication</a></span></dt><dd><dl><dt><span class="section"><a 
href="custom-auth.html#custom-auth-model">Guacamole's authentication 
model</a></span></dt><dt><span class="section"><a 
href="custom-auth.html#custom-auth-skeleton">A Guacamole extension 
skeleton</a></span></dt><dt><span class="section"><a 
href="custom-auth.html#custom-auth-building">Building the 
extension</a></span></dt><dt><span class="section"><a 
href="custom-auth.html#custom-auth-config">Configuration and 
authentication</a></span></dt><dt><span class="section"><a 
href="custom-auth.html#custom-auth-more-config">Parsing the 
configuration</a></span></dt><dt><span class="section"><a 
href="custom-auth.html#custom-auth-installing">Installing the 
extension</a></span></dt></dl></dd><dt><span class="chapter"><a 
href="writing-you-own-guacamole-app.html">20. Writing your own Guacamole 
application</a></span></dt><dd><dl><dt><span class="section"><a 
href="writing-you-own-guacam
 ole-app.html#basic-guacamole-architecture">The basics</a></span></dt><dt><span 
class="section"><a 
href="writing-you-own-guacamole-app.html#web-app-skeleton">Web application 
skeleton</a></span></dt><dt><span class="section"><a 
href="writing-you-own-guacamole-app.html#guacamole-skeleton">Adding 
Guacamole</a></span></dt><dt><span class="section"><a 
href="writing-you-own-guacamole-app.html#next-steps">Where to go from 
here</a></span></dt></dl></dd></dl></div></div><div class="navfooter"><hr 
/><table width="100%" summary="Navigation footer"><tr><td width="40%" 
align="left"><a accesskey="p" href="troubleshooting.html">Prev</a> </td><td 
width="20%" align="center"> </td><td width="40%" align="right"> <a 
accesskey="n" href="guacamole-protocol.html">Next</a></td></tr><tr><td 
width="40%" align="left" valign="top">Chapter 12. Troubleshooting </td><td 
width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td 
width="40%" align="right" valign="top"> Chapter 13. The Gu
 acamole protocol</td></tr></table></div>
+
+            </div></div>
+        <!-- Google Analytics -->
+        <script type="text/javascript">
+          
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+          (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new 
Date();a=s.createElement(o),
+          
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+          
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+          ga('create', 'UA-75289145-1', 'auto');
+          ga('send', 'pageview');
+        </script>
+        </body></html>
\ No newline at end of file

Reply via email to