GUACAMOLE-88: Add completed libguac-client-ball tutorial for reference.
diff --git a/tutorials/libguac-client-ball/.gitignore b/tutorials/libguac-client-ball/.gitignore
new file mode 100644
index 0000000..aeb5561
--- /dev/null
+++ b/tutorials/libguac-client-ball/.gitignore
@@ -0,0 +1,47 @@
+
+# Object code
+*.o
+*.so
+*.lo
+*.la
+
+# gcov files
+*.gcda
+*.gcov
+*.gcno
+
+# Backup files
+*~
+
+# Release files
+*.tar.gz
+
+# Files currently being edited by vim or vi
+*.swp
+
+# automake/autoconf
+.deps/
+.dirstamp
+.libs/
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache/
+m4/*
+!README
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+install-sh
+libtool
+ltmain.sh
+missing
+stamp-h1
+test-driver
+
diff --git a/tutorials/libguac-client-ball/Makefile.am b/tutorials/libguac-client-ball/Makefile.am
new file mode 100644
index 0000000..5c5eea7
--- /dev/null
+++ b/tutorials/libguac-client-ball/Makefile.am
@@ -0,0 +1,13 @@
+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
+noinst_HEADERS = src/ball.h
+libguac_client_ball_la_SOURCES = src/ball.c
+
+# libtool versioning information
+libguac_client_ball_la_LDFLAGS = -version-info 0:0:0
diff --git a/tutorials/libguac-client-ball/configure.ac b/tutorials/libguac-client-ball/configure.ac
new file mode 100644
index 0000000..df49a1a
--- /dev/null
+++ b/tutorials/libguac-client-ball/configure.ac
@@ -0,0 +1,19 @@
+# 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_LIBTOOL
+
+# Check for libguac (http://guac-dev.org/)
+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
diff --git a/tutorials/libguac-client-ball/src/ball.c b/tutorials/libguac-client-ball/src/ball.c
new file mode 100644
index 0000000..2dcc966
--- /dev/null
+++ b/tutorials/libguac-client-ball/src/ball.c
@@ -0,0 +1,201 @@
+#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>
+
+/* Client plugin arguments (empty) */
+const char* TUTORIAL_ARGS[] = { NULL };
+
+void* ball_render_thread(void* arg) {
+
+    /* Get data */
+    guac_client* client = (guac_client*) arg;
+    ball_client_data* data = (ball_client_data*) client->data;
+
+    /* 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 == GUAC_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 * 1000);
+        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;
+
+        /* 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);
+
+        /* Update timestamp */
+        last_frame = current;
+
+    }
+
+    return NULL;
+
+}
+
+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;
+
+    /* Get user-specific socket */
+    guac_socket* socket = user->socket;
+
+    /* Send the display size */
+    guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, 1024, 768);
+
+    /* 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);
+
+    /* Fill with texture */
+    guac_protocol_send_rect(socket, GUAC_DEFAULT_LAYER,
+            0, 0, 1024, 768);
+
+    guac_protocol_send_lfill(socket,
+            GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
+            texture);
+
+    /* Set up ball layer */
+    guac_protocol_send_size(socket, ball, 128, 128);
+
+    /* Fill with solid color */
+    guac_protocol_send_arc(socket, data->ball,
+            64, 64, 62, 0, 6.28, 0);
+
+    guac_protocol_send_close(socket, data->ball);
+
+    guac_protocol_send_cstroke(socket,
+            GUAC_COMP_OVER, data->ball,
+            GUAC_LINE_CAP_ROUND, GUAC_LINE_JOIN_ROUND, 4,
+            0x00, 0x00, 0x00, 0xFF);
+
+    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);
+
+    /* 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;
+
+    /* Wait for render thread to terminate */
+    pthread_join(data->render_thread, NULL);
+
+    /* 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);
+
+    /* 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);
+
+    /* This example does not implement any arguments */
+    client->args = TUTORIAL_ARGS;
+
+    /* Client-level handlers */
+    client->join_handler = ball_join_handler;
+    client->free_handler = ball_free_handler;
+
+    return 0;
+
+}
diff --git a/tutorials/libguac-client-ball/src/ball.h b/tutorials/libguac-client-ball/src/ball.h
new file mode 100644
index 0000000..7a7d5e4
--- /dev/null
+++ b/tutorials/libguac-client-ball/src/ball.h
@@ -0,0 +1,22 @@
+#ifndef BALL_CLIENT_H
+#define BALL_CLIENT_H
+
+#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;
+
+#endif