This manual describes gzochid, the gzochi server.
Copyright © 17 March 2013 Julian Graham.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.
This reference manual documents gzochid, the server component of the gzochi massively multiplayer online game development framework.
Getting started
The gzochid container
Writing applications for gzochid
Appendices
Indices
gzochid is the server component for the gzochi massively multiplayer online game development framework. It is responsible for hosting the server-side portions of game applications developed against the framework, for managing the data persisted by these applications and provisioning computing resources for their needs at run-time, and for exposing a set of container services that are especially useful for online game development.
gzochid is a container for game server applications the same way that a web container is a container for web applications: It manages the lifecycles of the applications it hosts, routes client requests to application endpoints, and provides services to ease the interaction of the applications with external resources.
This manual expects a familiarity with the Scheme programming language, which is the language used to write applications that can be hosted by gzochid. gzochid uses the GNU GUile extension language platform to provide its Scheme run-time environment; the Guile manual is an excellent resource for users who are new to Scheme or to functional programming in general.
New users of gzochi may wish to pay special attention to the following section of this manual, “Conceptual overview,” which explores some of the rationale for the design of the gzochi framework and the services it provides.
Developing games that are played over a computer network poses challenges distinct from those that arise from games whose extent is limited to a single process or a single machine. The characteristics of the network link that connects the machines involved the game give rise, by necessity, to some primary constraints on the design of the game: To create a dynamic model of the game state that is shared between the client and the server, those systems must exchange messages, and this process is naturally limited by the rate of message delivery. Will messages be delivered reliably? Is message order guaranteed to be preserved? Answers to these questions will also have an impact on game server architecture.
When multiple players are allowed to interact with a networked game system simultaneously, an additional set of difficulties emerges. How can their interactions with components of the game system be properly synchronized such that each player receives a fair and consistent view of the world? How can this synchronization be scaled to maintain a responsive user interface for up to thousands of simultaneously connected clients?
Some additional background is presented in the following sections. To address these issues, gzochid provides a unified set of software tools, which are described in a subsequent chapter (see Application services).
If the state of a game is to “outlive” the server process that manages it, the data that makes up the state must be written to non-volatile storage, such as a hard disk. There are many reasons for a server process to terminate. Some shutdowns, such as those performed for system maintenance or upgrades; others are spontaneous—software bugs are inevitable, and whether they cause the server process to terminate outright or leave the game system in an unplayable state, the net effect is the same. When a player's commitment to an online game can span months or even years, losing their play history can be quite disheartening.
Several questions must be answered in order for persistence to be implemented: How often must data be persisted? If players are notified of changes to game state before these changes are made persistent, then the potential exists for a recovered game state to “erase” progress made by players between the last persistence event and the shutdown of the game. On the other hand, non-volatile storage media are often quite a bit slower than random-access memory, and thus forcing persistence too often can create a bottleneck on game performance. How much of the game state must be persisted at each persistence point to ensure that the entire state can be reconstituted at some later date? For large, complex games, the game state may be so large that persisting the entire state takes so long that even infrequent persistence events must cause the game to “pause.” If only portions of the game state are persisted, then care must be taken to ensure that enough state is persisted to ensure logical consistency between entities within the game.
gzochid addresses these issues with an automatic persistence mechanism that treats game state as an object graph in which updates are tracked and persisted transparently, with full transactional semantics. See Managed records, for more information.
It is often important that certain sequences of events occur as a unit, such that either every event in the sequence takes place (and players receive notification) or, in the event of an error, none of the events take place—no matter where in the sequence the error arises. One example of this is transferring an object from one the inventory of one player to the inventory of another. Depending on how the transfer is implemented, there may be an interval between the object being taken from the first player but before it is given to the second player. If the execution of game code is interrupted at this point, the object may be destroyed. A similar problem arises if a reference to the object is given to the second player before being removed from the first.
Even when errors are detected, recovery can difficult: It may not be possible to determine what the state of individual connected clients is once they have lost consistency with the server's model of the game world, and enabling clients to resolve conflicting updates to game state presents significant architectural challenges. In general, once the side effects—e.g, client notifications or persistent changes to data—have been committed, they cannot easily be undone.
gzochid executes all game application code in a transactional context, meaning that the side effects produced by a portion of code are delayed until its successful completion, at which point all of them guaranteed to take effect together; or the side effects are “rolled back” and the block of code is either retried, with no indication to the client that an error occurred, or abandoned. And other portions of code that are concurrently accessing the same bits of data are guaranteed a consistent view of that data for the duration of their execution.
The reliable delivery of messages between clients and the server is fundamental to the operation of an online game, but the network communication services provided by most programming languages and operating systems expose game applications to nuanced, unpredictable behaviors. Some communication channels do not guarantee packet delivery; nor is in-order delivery alway ensured. Even if a system promises ordered and reliable ordered delivery of packets, it is difficult to predict their time of delivery.
When a packet of data arrives on the client or server, the bytes it contains must be interpreted, a process that is governed by a shared protocol. The set of possible communications between hosts in an online game is naturally dependent upon the specific mechanics of that game, but some types of messages are likely common to all games: Clients need to establish their identities with the server; the server needs to respond to authentication attempts. The client and server may need messages representing attempts to disconnect or log out of the game gracefully. Some types of messages, which trigger transitions in the state of a client's connection to the server, are only valid when the connection is in a particular state. What should be the response from the server if it receives a login request from an already-authenticated client in the course of regular gameplay? If there are multiple points in the flow of game execution at which messages can be received, does semantic validation of message content have to be applied at all of them?
Because the state of a network connection is dependent on the state of multiple independent hosts and their operators, it is inherently asynchronous with game state. In the likely case that a protocol message is larger than a single packet, an entire message may not become available all at once, and thus participants in the communication will need to keep a buffer of partial messages while they wait for the remaining bytes. A connection may be interrupted before all of the message's consituent packets have been delivered, and if the processing of network data is mixed in with the processing of game application logic, recovery from a network failure may be complicated.
There are aspects of multiplayer games for which it is not very important that every player have a view of the world that is consistent with that of every other player. For example, depending on the context, it may not be critical that every player have the same information about the scenery in a particular region—this is information that is related to the game world, but has no bearing on the outcome of the game. There are other elements of gameplay for which it is necessary that all involved players are kept in a consistent state. If some but not all players receive notification of a change that does affect the outcome of the game, not only are they at a strategic disadvantage, but losing synchronization with the server's model of the world may make it difficult for them to interpet subsequent notifications.
gzochid provides a network management layer and a low-level client-server protocol that work in concert to hide the tricky details of message deliery. Reasonably large messages may be transactionally queued for delivery to the server or its clients, and messages can be addressed to individual clients or to arbitrarily large groups of clients with a single procedure invocation. See Client session management, for information on gzochid's representation of client connections; See Channel management, for a description of efficient message broadcast services.
While some portions of a game can be driven entirely by client-generated events, there are often flows of execution that are best managed as “background processes” that proceed independent of any action by a client. Some examples of this type of processing include: Time and weather systems, in which regular changes to the game world take place at scheduled intervals; or the actions of non-player characters that act as autonomous agents within the game world, with a flow of logic that determines their behavior based on various dynamic game states.
As you can infer from these examples, different modes of scheduling and execution are possible for tasks within the same application. Some tasks need to begin executing at predetermined points in the future. Others need to run as soon as CPU time can be allocated to them. Certain tasks, such as those implementing an in-game timer tick, for example, may need to execute on a repeating basis.
This type of asynchronous parallelism could be implemented using a an explicitly threaded execution model, but this approach has some significant limitations. For one, allocating a new thread for every asynchronous bit of processing to be done consumes valuable process memory and CPU cycles, and effectively constrains the amount of work that can be . A thread pool can some of these issues, but few low-level thread libraries include time-based scheduling as part of their thread management APIs—you can specify that some bit of code should run in a separate thread but, but you usually can't control when it runs or how often it repeats without building some abstractions around the system's thread primitives.
gzochid provides scheduling and execution services that allow tasks to be queued for immediate or deferred processing, either one time only or repeating on a configurable interval. Furthermore, gzochid provides durability guarantees about scheduled tasks to the effect that tasks that fail with a recoverable error can be retried, and that the universe of scheduled tasks can survive a failure and restart of the application server. See Task scheduling, for more information.
See the INSTALL file included in the gzochid distribution for detailed instructions on how to build gzochid. In most cases, if you have the requisite toolchain and dependences in place, you should simply be able to run
./configure
make
make install
This will install the gzochid executable gzochid to a standard location, depending on the installation prefix—on most Unix-like systems, this will be /usr/local, with executable files being copied to /usr/local/bin. A server configuration file with the default settings will be installed to the /etc/ directory under the installation prefix.
This configuration file (gzochid.conf) will be processed prior to installation to set references to the gzochid deployment and data directories—where the server looks for deployed games and where it stores game state data, respectively—to locations relative to the installation prefix. See The server configuration file, for more information.
The format for running the gzochid program is:
gzochid option ...
With no options, gzochid scans its deployment directory looking for game applications, each of which is configured and initialized or restarted depending on its state, and then begins listening for client connections. By default, the monitoring web application is also started.
In the absence of command line arguments, the port numbers on which these servers listen for connections, as well as other aspects of their behavior, are modifiable via a configuration file (see below).
gzochid supports the following options:
The gzochid server configuration file is usually named gzochid.conf and is installed (and searched for) by default in the /etc/ directory of the installation prefix. It is an .ini-style configuration file, meaning it consists of several named sections of key-value pairs, like so:
[section]
key1 = value1
key2 = value2
The configuration options currently understood by gzochid are as follows, organized by section.
admin
These settings control various aspects of gzochid's administrative and monitoring functionality.
true to enable the administrative context, which is
responsible for collecting and reporting on a variety of statistics
about the state of a running gzochid server and its hosted games.
Disabling this feature (by setting this key to false) will
net a small improvement in process memory consumption and CPU
performance.
true to enable the debugging server. Has no effect if
‘context.enabled’ is not true.
true to enable the monitoring web server. Has no
effect if ‘context.enabled’ is not true.
game
These settings control the primary game server module of gzochid.
By design, this setting has an impact on the task execution throughput of game applications. The longer a task takes to execute, and the more data it accesses as part of its execution, the more constraints it places on the transactional work that can be done concurrent with its execution. As a corollary, the shorter a task's duration and the less data it accesses, the less risk there is that it will conflict with other tasks. Before increasing this value beyond its default, consider refactoring a failing task to perform fewer operations and access less data.
Certain lifecycle events, such as application initialization, are executed in transactions without time limits; this setting has no effect on the processing of those events.
log
These settings control the system-wide logging behavior of gzochid.
ERR,
WARNING, NOTICE, INFO, and DEBUG.
Game applications hosted by gzochid are discovered by the server when it scans its deployment directory for sub-directories containing game application descriptor files, which are discussed in the following section. If gzochid's game deployment directory is “/var/gzochid/deploy” (the default), then the server will scan and discover the game descriptor file “/var/gzochid/deploy/my-game/game.xml” on startup.
The other required components of a game application are the Guile Scheme modules that contain the game logic and callbacks. These are typically included in sub-directory trees rooted in the game application directory, but alternate locations to search for modules can be specified in the game application descriptor file.
“game.xml,” the game application descriptor, is an XML document that is deployed as part of a game application and provides game configuration information and metadata to gzochid. It is a rough analog to the “web.xml” descriptor file that accompanies Java web applications. Like “web.xml,” “game.xml” is used by the server to find the locations of the application's code libraries and the entry points to the application. The game descriptor file must appear in the deployed application's root directory.
A DTD that can be used to validate the structure of your application descriptors is included in the gzochid source distribution. Some explanation of the semantics of the descriptor file follows.
The application descriptor's document element is game, and it
must include a name attribute that specifies a unique
“short name” for the application; among other things, this name
will be used to identifier your application in log messages.
The description element allows you to specify as its content
some longer, more descriptive text to identify your game. (This text
will be displayed in the gzochid monitoring console.)
The load-paths element is a wrapper element for zero or more
load-path element, each of which specifies as its content an
absolute or relative path to be (temporarily) added to the default
Guile %load-path variable, which contains the locations that
are searched during module resolution. Note that the game
application root directory is always added to the load path, so you
can leave the load-paths element empty if your application
library tree is rooted at the application root.
Next there are two “lifecycle callbacks” that must be specified,
procedures for handling the “initialization” and “logged in”
events. Callbacks are specified via a callback element, which
has no content but requires the procedure and module
arguments which specify a publicly-visible Scheme procedure to be
used to handle an event. For example, the following XML snippet:
<callback procedure="handler" module="my-code app handlers" />
...identifies the handler procedure exported from the Guile
module (my-code app handlers). Modules are resolved via the
configured load paths.
Initialization occurs once per application—even across server restarts—and the initialization callback is passed an R6RS hashtable containing application properties. (In the current release, this table will always be empty.) The logged in callback will be called when a client connects and successfully authenticates, and it will be passed a client session record that can be used to communicate with the connected client.
The follow sections describe the services that gzochid exposes to the applications it hosts. As an application author, you are free to employ or ignore them in whatever proportion you choose, but the expectation is that most non-trivial games will depend heavily on all of the services the container provides.
All game application code that executes within the gzochid container executes in the context of a transaction, meaning that all of its side effects, such as sending messages or modifying data, have the four ACID properties: Atomicity, consistency, isolation, and durability. The services described in the following sections are the primary means by which side effects are achieved in a gzochi application, and all of them participate in the container's two-phase commit protocol, which verifies that each participant is prepared to commit before issuing the request to do so.
When a transaction commits, the side effects requested from each service by application code are made permanent: Messages are sent to clients, changes to data are saved to the data store. When a transaction fails to commit, each service participating in the commit rolls back any transaction-local state that was created during the lifetime of the transaction.
A transaction may fail to commit for any of several reasons: It may
have exceeded the maximum running specified by the tx.timeout
setting; it may have attempted to access data in a way that brought
it into conflict with another currently-executing transaction; an
external resource (such as a network connection) required by the
transaction may be unavailable; code executing in a transactional
context may exit non-locally. If a transactional task or callback
fails to commit but the container determines that it is safe and
desirable to re-attempt it, it will automatically be returned to the
queue of items eligible for execution. A transactional unit of work
that fails in a “retryable” way will be retried up to a configured
maximum number of times (3, by default) before being abandoned.
gzochid exposes its transactional persistence services via
flexible, user-defined data structures called “managed records.”
A managed record is just like an R6RS record—in fact, a managed
record is an R6RS record that has the record-type
gzochi:managed-record as its parent—with a few additional
rules. First of all, managed record-type definitions must be unique
according to the R6RS record specification, and so a
nongenerative clause will be automatically created if it is
not specified as part of a syntactic record type definition form;
when defining a type procedurally, the record's name will be used if
the uid argument is #f.
Second, the fields of a managed record must be annotated to assist the container in persisting them to the data store. This is done via a serialization clause added to every field sub-clause in the managed record definition. The serialization clause gives a reference to the serialization to use to convert the field value to and from a stream of bytes as it is written to and read from the data store. A serialization is a record that provides serializer and deserializer procedures that are called by the container during the persistence phrase for managed records that have been modified in a transaction. The serialization clause may be omitted for fields whose value will always be a managed record. In this case, a built-in managed record serialization will be used. See gzochi io, for more information on serialization.
For parity with the R6RS record libraries, the gzochid Scheme API provides both syntactic and procedural facilities for working with managed records. See gzochi data, for more information on creating managed records.
gzochid provides a few different ways of accessing data persisted as managed records. You can access persistent data implicitly, in the form of a managed record used as a callback for a lifecycle event (e.g., client messages); or you can bind managed objects to names for explicitly retrieval. In either case, the container will also manage the persistence of managed records reachable from the root record—that is to say, gzochid knows when a field in one managed record contains a reference to another managed record and only persists the portions of the object graph that change during the execution of application code.
Like the rest of the operations provided by the container, access to data follows transactional semantics. Any single flow of execution within an application is guaranteed a consistent view of data over the lifetime of its execution, and the set of changes it makes to data during this lifetime will be persisted together or not at all. These operations are also subject to transactional constraints, such as the requirement that they complete within a configured timeout and that they not conflict with operations accessing the same data in other transactions. If these constraints are violated, the operation will fail and the task will be retried or abandoned.
Bindings can be manipulated using the gzochid:set-binding!,
gzochid:get-binding and gzochid:remove-binding!
procedures. For example, the following code snippet introduces a new
binding that refers to a field of the managed record obj:
(define obj (gzochi:get-binding "my-object"))
(gzochi:set-binding! "f" (my-object-field obj))
Note that the container tracks references to managed records such
that at any subsequent point (provided the bindings above are not
mutated), the following expression will evaluate to #t:
(eq? (my-object-field (gzochi:get-binding "my-object"))
(gzochi:get-binding "f"))
See gzochi data, for more information.
A connected and authenticated user is exposed to game code in the form of a client session, a managed record that can be used to manipulate the state of that user. Messages may be queued transactionally for delivery to individual client sessions or to groups of sessions (see below); sessions can be explicitly disconnected; and handlers may be registered for session-related events, such as incoming messages and client-side disconnections.
Because client sessions are managed records, they can be used any place in game application code that managed records may be used, such as automatically serialized fields of other managed records or as the data for an event handler. See gzochi client, for more information.
Message broadcasting is a pattern that appears frequently in massively multiplayer game development. There may be a logical set of players that should be managed and addressed by the server as a group for the purposes of messaging. This group may include every player in the game, in the case of system notifications that need to be sent globally; or it may correspond to a logical grouping arising from game logic, such as broadcasting messages only to players gathered in a particular room or region.
gzochid addresses this case by providing an abstraction for managing communication with arbitrarily large numbers of grouped client sessions. gzochid “channels” are managed records, and, like client sessions, can be used any place in game application code that supports managed records. See gzochi channel, for more information.
gzochid provides an explicit task scheduling API that is used in place of other mechanisms for asynchronous processing, such as threads. A task in gzochid is a callback similar to the ones invoked for application lifecycle events, such as initialization; it specifies a procedure to execute (qualified by a Guile module name), accompanied optionally by an arbitrary managed record to supply contextual information.
The task API provides several options for task scheduling. Scheduling is a transactional operation with respect to the code doing the scheduling, so the earliest a scheduled task can run is following a successful commit of the transactional code (a task or a lifecycle callback) that scheduled it. Additionally, the execution of a task may be delayed by a user-specified number of milliseconds. If a task needs to run more than once, you can reschedule it explicitly as part of its execution, or you can schedule it as a periodic task. Periodic tasks are automatically rescheduled to run on a repeating basis with each execution following the previous one after a specified number of milliseconds.
Task scheduling is persistent, such that the schedule of pending tasks will survive a restart of the gzochid container. See gzochi task, for more information.
Because gzochid executes application code transactionally, any side effects (e.g., queued messages, scheduled tasks) will be rolled back if the enclosing transaction fails to commit. And a single task may be executed several times before committing successfully if there is heavy contention for data or other resources. As such, if log messages are written non-transactionally, it can be difficult to use them to trace application events.
The gzochid container provides an API for writing log messages that will only be flushed on a successful commit. For example, if the following segment of transactional code is attempted and rolled back twice before committing:
(display "A log message.") (newline)
(gzochi:info "A transactional log message.")
...the output might include:
A log message.
A log message.
A log message.
A transactional log message.
See gzochi log, for more information.
The protocol used for gzochi client-server communication is documented below. Note that this description is provided merely for the curious; the responsibility of gzochi game developers is to handle the messages that this underlying protocol delivers—in the form of byte arrays—to the client or server. The format and encoding of these byte arrays is left up to game developers to determine.
The low-level protocol described below conforms to a general pattern of a two-byte prefix encoding the length of the message payload, if any, followed by an “opcode” indicating the purpose of the message. (The opcode byte is not included in the length prefix.) The maximum size of a message body sent between components in a gzochi game is thus 65535. Note that this is not necessarily the size of the packet that delivers the message; the client and server may break a larger protocol up into smaller packets that are re-assembled by the recipient. (Naturally, this behavior is transparent to gzochi game developers.)
The following table lists the message types and structures that make up the low-level gzochi byte protocol.
LOGIN_REQUEST (0x10)LOGIN_SUCCESS (0x11)LOGIN_REQUEST was
received and that authentication was successful. There is no message
payload for this message.
LOGIN_FAILURE (0x12)LOGIN_REQUEST was
received but that the login could not be completed successfully.
LOGOUT_REQUEST (0x20)LOGOUT_SUCCESS (0x21)LOGOUT_REQUEST
message was received. There is no message payload for this message.
Following the dispatch of this message, the server will close the
client's socket connection.
SESSION_DISCONNECTED (0x30)SESSION_MESSAGE (0x31)gzochid employs a pluggable authentication mechanism to allow each game application endpoint to specify an authentication scheme that meets its security requirements. The plugins currently available are listed below.
When enabled, the gzochid administrative module collect various bits of statistical information and makes resources related to active game applications available for reporting. The module's architecture supports the registration of sub-modules—described below—that expose this information in different ways.
The monitoring web server
When the monitoring web server is enabled, it listens for HTTP connections on its configured port (8080 by default) and serves HTML pages with information about the server and the games it runs. In particular, a browser for the game applications' data stores is provided, which renders the contents of the store in a format similar to a “hex editor” application. There are two ways of accessing the data store through the monitoring web server. The binding list can be accessed by visiting the following URL in a web browser:
http://localhost:8080/app/my-game/names/
Provided the server is running on the local machine and listening on port 8080, the URL above will return a list of bound names in the data store for ‘my-game’, with links to the data bound to each name. For a lower-level view of the store, you can visit the URL:
http://localhost:8080/app/my-game/oids/
...which serves a list of all of the managed records in the store, indexed by the internal object identifiers the container uses to track them.
Future plans for the monitoring web server include per-game statistical reporting on data such as transactional throughput and client session volume.
Application code deployed to gzochid executes in a context with fairly unique characteristics. Even when unit tests—which should be the primary means of detecting and preventing bugs—have been written, situations present themselves in which inspecting the state of a running application is the most effective way to troubleshoot an error or incorrect behavior. To this end, gzochid offers a remote debugging interface that allows a developer to connect to a running gzochid instance using a telnet client and to evaluate Scheme code within the context of an application hosted by that instance.
The debugging server listens on the port specified by the
module.debug.port setting in the server configuration file.
When a client connects to the debug port, a new Scheme REPL (Read
Evaluate Print Loop) is launched and associated with a fresh
“sandbox” environment in which the (guile),
(gzochi), and (gzochi admin) modules have been
pre-loaded. A user can interact with the debugger using the full
complement of Scheme syntax and Guile REPL commands
(e.g., ,pretty-print). A typical debugging session might have
the form:
julian@navigator:~$ telnet localhost 37146
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GNU Guile 2.0.6.31-2446f
Copyright (C) 1995-2012 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.
Enter `,help' for help.
scheme@(#{ g109}#)> (gzochi:applications)
$1 = (#<r6rs:record:gzochi:application-context>)
scheme@(#{ g109}#)> (gzochi:with-application (car $1)
(lambda () (gzochi:get-binding "scoreboard")))
$2 = #<r6rs:record:my-game:scoreboard>
As the introduction to this manual explains, gzochid is a server container for gzochi game applications. To take full advantage of this architecture, it may be useful to understand the way gzochid interacts with your application.
There are several entry points to a game application. When an application is started for the first time, its initialization procedure is invoked. This procedure is responsible for setting up any global state required by the game and creating any managed record bindings that must be present before client connections can be accepted. The game application descriptor also registers a callback procedure that is invoked when a new, authenticated client connection is established. See the
The following paragraphs are describe some best practices for game programming in gzochid.
Avoid top-level Scheme bindings for application state.
Modifications to data accessed via bindings in the top-level module
environment (i.e., variables created using define) cannot be
tracked by gzochid, whether the data is part of a managed record or
not. To share mutable state between different execution paths in a
game application, bind the state to a name with the gzochid binding
API and retrieve and modify its value—creating a local definition
via a let form, perhaps—within the scope of the code that
needs it. There is no need to synchronize access to data managed by
gzochid; the container will prevent race conditions by rolling back
task execution as necessary.
Express concurrency through task scheduling.
Likewise, you should never need to explicitly launch a thread to handle a bit of application work. Scheduling work via gzochid's task API ensures that it is executed in the proper transactional context and that it will be transparently rescheduled following a non-fatal error and that its status will survive the failure and restart of the container.
Limit task scope.
The longer a task runs and the more resources it accesses, the more
likely it is to disrupt the behavior of other
simultaneously-executing tasks, and the less likely its transaction
will be able to commit successfully—tasks whose execution time
exceeds the configured value of tx.timeout will be aborted or
otherwise prevented from committing. If there is a lot of work to be
done or there are many objects to be modified, try breaking a large
task into a series of smaller tasks, each of which does a portion of
the work and then schedules the next portion to run as soon as
possible.
Avoid external side effects.
Because application tasks are executed within the scope of a transaction that may be rolled back and re-attempted arbitrarily many times, any side effects these tasks have that are not managed by gzochid may be “played back” multiple times along with the rest of the task's execution, possibly duplicating their impact.
The following sections describe the Scheme API exposed to the
server-side components of gzochi applications by the gzochid
container. The API consists of a set of use-specific R6RS libraries
that can be imported independently or all together via the
(gzochi) composite library.
The (gzochi admin) module exports procedures and data types
that enable introspection of game application state and the
execution of Scheme code within the context of a running game
application.
These functions are intended for use with the remote debugging
interface provided by the gzochid container. Because their use cases
as part of deployed application code are not well defined, they are
not exported from the (gzochi) composite library.
Returns a list of application context objects representing the set of applications running in the container.
Returns an application context representing the “current” application, e.g. as set by
gzochi:with-application, or#fif the current application has not been set.
Returns
#tif obj is an application context object (as returned bygzochi:applicationsorgzochi:current-application,#fotherwise.
Returns the name of the application represented by the application context object context.
Calls the zero-argument procedure thunk with the current application set temporarily to the application represented by the application context object context. The value yielded by
thunkis returned.The application that was current before calling
gzochi:with-application(or#fif there was none) will be restored when thunk exits locally or non-locally.
The (gzochi app) module exports procedures and data types
common to other components of the API.
Callbacks are serializable references to Scheme procedures with some optionally associated data. They are used in several places to indicate actions to be taken by game application code upon notification of an asynchronous event such as a new autheticated client connection. Procedures are represented within callbacks as Scheme symbols; the modules that export them are represented as lists of symbols. The data associated with a callback—if any—must take the form of a managed record, so that its lifecycle may be managed by the container.
Constructs a new
gzochi:callbackwith the specified procedure, module, and optional data.
Returns the module specification for the
gzochi:callbackcallback as a list of symbols.
Returns the procedure name for the
gzochi:callbackcallback as a symbol.
Returns the managed record that encapsulates the data for the
gzochi:callbackcallback or#fif the callback was created without any.
The value of this fluid is set to the root deployment directory of the application to which the currently executing code belongs. (By default, this is “/var/gzochid/deploy/[application name]”.)
The (gzochi channel) library exports procedures that are
useful for managing client communication channels.
Creates and returns a new channel bound to the string specified by name. A
&gzochi:name-existscondition will be raised if there is already a channel with that name.
Returns the channel bound to the specified string name, which must have been created previously via a call to
gzochi:create-channel. A&gzochi:name-not-boundcondition will be raised if there is no channel wit
Returns the name of the channel channel as a string.
Adds the client session session to the channel channel. session is guaranteed to receive any messages successfully committed following the successful commit of the join operation.
Removes the client session session from the channel channel. session is guaranteed not to receive any messages committed following the successful commit of the leave operation.
Enqueues a message to be sent, in the form of the bytevector msg, to all client sessions that are members of the channel channel at the time this procedure is called.
Destroys the channel channel, unbinding its associated name and removing all constituent client sessions.
The (gzochi client) library provides procedures that are
useful for working with individual client sessions.
See (gzochi channel), for functionality related to groups of
client sessions.
Client sessions are managed records; as such, you may store a
session as the value of fields in other managed records or as the
data for tasks or other callbacks. When a client is disconnected,
the session record is removed from the data store, and attempts to
access it will result in a &gzochi:object-removed condition
being raised.
Returns
#tif obj is a client session record,#fotherwise.
Returns the identity associated with the session session as a string. The game's authentication plugin is responsible for setting the session's identity.
Enqueues a message to be sent, in the form of the bytevector msg, to the client session session.
Client session listeners are managed records that are used by the
gzochid container to notify game application code of events related
to client sessions. A listener is returned from the callback for the
logged in event to indicate a successful login handshake
(#f may be returned instead to signal a login failure.) This
listener must in turn be configured with two gzochi:callback
objects, one to be invoked when a new message is received from the
spcified session, the other to be invoked when the session
disconnects from the server.
The record type, for introspection or use as a base type.
Constructs a new
gzochi:client-session-listenerwith the specifiedgzochi:callbackobjects received-message and disconnected, which will be invoked, respectively, when a message is received from a client and when a client disconnects from the server.
Returns
#tif obj is agzochi:client-session-listener,#fotherwise.
Returns the
gzochi:callbackregistered with thegzochi:client-session-listenerlistener for handling received messages.
Returns the
gzochi:callbackregistered with thegzochi:client-session-listenerlistener for handling session disconnection.
The (gzochi conditions) library exposes condition types and
related procedures for conditions that may be raised during the
execution of game application code.
A &gzochi:name-exists condition is raised in contexts in
which an attempt is being made to introduce a new binding, but the
target name is already bound.
The condition type, for introspection or use as a base type for other conditions.
Contructs a new
&gzochi:name-existscondition for the specified name string name.
Returns
#tof obj is a&gzochi:name-existscondition,#fotherwise.
Returns the name associated with the specified
&gzochi:name-existscondition cond.
A &gzochi:name-not-bound condition is raised in contexts in
which a non-existent named binding is looked up.
The condition type, for introspection or use as a base type for other conditions.
Contructs a new
&gzochi:name-not-boundcondition for the specified name string name.
Returns
#tof obj is a&gzochi:name-not-boundcondition,#fotherwise.
Returns the name associated with the specified
&gzochi:name-not-boundcondition cond.
A &gzochi:object-removed condition is raised in contexts
when a reference to a managed record is accessed after the record
has been removed. This may happen for a number of reasons: A client
session record used as a field value or binding and which is
subsequently disconnected; a named binding whose target value is
explicitly removed; or a managed record used as a value that is
accessed after it is has been explicitly removed.
The condition type, for introspection or use as a base type for other conditions.
Contructs a new
&gzochi:object-removedcondition.
Returns
#tof obj is a&gzochi:object-removedcondition,#fotherwise.
A &gzochi:no-current-application condition is raised when an
operation requiring an application context is attempted and none is
present. This happens most frequently because of user error in an
interactive remote debugging session—for example, a call to a
transaction-aware API function that is not wrapped in an
invocation of gzochi:with-application.
The condition type, for introspection or use as a base type for other conditions.
Contructs a new
&gzochi:no-current-applicationcondition.
Returns
#tof obj is a&gzochi:no-current-applicationcondition,#fotherwise.
A &gzochi:transaction-aborted condition is raised when a
transactional operation is attempted and the transaction bound to
the current thread has been found to be in an inconsistent
state—that is to say, it has been rolled back or marked for
rollback.
Although this condition will almost aways be raised in a non-continuable way, aborted transactions are an expected part of the control flow of a gzochi game application. A transaction may be aborted for a number of reasons; the code executing as part of the transaction may have accessed data in a way that brought it into conflict with code executing as part of another transaction, or its execution time may have exceeded a configured threshold and the scheduler has pre-emptively aborted its transaction to prevent it from interfering with other transactions.
A &gzochi:transaction-aborted condition does not typically
require explicit handling. Rather, it is best to allow the code that
triggered the condition to exit non-locally; gzochid's task
scheduler will observe the state of the transaction upon exit and
reschedule the task or callback accordingly.
The condition type, for introspection or use as a base type for other conditions.
Contructs a new
&gzochi:transaction-abortedcondition.
Returns
#tif obj is a&gzochi:transaction-abortedcondition,#fotherwise.
A &gzochi:transaction-retry condition is raised when a
transactional operation or an interaction with the gzochi API fails
but is safe to retry and worth retrying because it might succeed on
a subsequent execution attempt. This condition is often raised as a
composite condition with a &gzochi:transaction-timeout
condition when a task's execution times out. The container's Scheme
interface recognizes this condition type, and the container uses it
as part of determining whether to reschedule or abandon a task.
Application code may raise this condition explicitly, so as to release resources if it can determine ahead of time that the current transaction will not be able to commit.
The condition type, for introspection or use as a base type for other conditions.
Constructs a new
&gzochi:transaction-retrycondition.
Returns
#tif obj is a&gzochi:transaction-retrycondition,#fotherwise.
A &gzochi:transaction-timeout condition is raised when a
transactional operation takes longer than the time remaining for the
current transaction to run, or when the current transaction attempts
a transactional operation after its allotted running time has
elapsed.
The condition type, for introspection or use as a base type for other conditions.
Constructs a new
&gzochi:transaction-timeoutcondition.
Returns
#tif obj is a&gzochi:transaction-timeoutcondition,#fotherwise.
The (gzochi data) library exports the data structures and
procedures that make up gzochid's data storage and serialization
API. As discussed in a previous section, managed records are the
foundation of any game application's interaction with container's
data services. The syntactic and procedural APIs for managed records
are discussed below.
Note that because managed records are implemented on top of R6RS
records, they may be treated as such for the purposes of the
procedures in the (rnrs records inspection) library.
Defines a new managed record type, introducing bindings for a record-type descriptor, a record constructor descriptor, a constructor procedure, a record predicate, and managed accessor and mutator procedures for the new managed record type's fields.
The structure of name-spec and the record-clause sub-forms are the same as in the R6RS
define-record-type, with the following exceptions:First, as all managed records are nongenerative, if a
nongenerativeclause is not present as one of the record-clause sub-forms—or if theuidcomponent of this clause is not specified—then the record name will be used as the record type's uid.Second, each field definition that appears in a
fieldsdeclaration of arecord-clausesub-form of a managed record definition may include a serialization specification that provides the serialization to use for the field when it is marshalled to or from persistent storage. This specification has the form(serialization s), where s is agzochi:serializationrecord. If the serialization specification is omitted, the container will use a default serialization that requires all field values to be managed records themselves or#f.
Evaluates to the managed record-type descriptor associated with the type specified by record-name.
Evaluates to the managed record-constructor descriptor associated with the type specified by record-name.
Returns a new record-type descriptor for the managed record with the specified properties, which have the same semantics as they do when passed to R6RS's
make-record-type-descriptor, with the following exceptons that if uid may not be#f, an&assertioncondition will be raised; and the field descriptors in fields may contain serialization specifiers as described above.
Returns the managed record field accessor procedure for the kth field of the managed record-type descriptor mrtd.
Returns the managed record field mutator procedure for the kth field of the managed record-type descriptor mrtd. An
&assertioncondition will be raised if this field is not mutable.
Returns a constructor procedure for the managed record constructor descriptor mrcd. This procedure returns the same value as the
record-constructorprocedure in the(rnrs records procedural)library.
These procedures return the same values as their counterparts in the
(rnrs records procedural)library.
Returns the record-type descriptor for mr. This procedure returns the same value as the
record-rtdprocedure in the(rnrs records procedural)library.
References to managed records within an object graph of other managed records will be tracked transparently by the container. The following procedures can be used to explicitly store and retrieve references to managed records by name.
Returns the managed record associated with the strig name name. A
&gzochi:name-not-boundcondition will be raised if there is no binding for name.
Creates an association between the string name and object, which must be a managed record, replacing any previous binding that may exist for name.
Removes the binding for the string name. A
&gzochi:name-not-boundcondition will be raised if there is no binding for name. Note that this procedure only removes the association between name and a managed record; to remove the record itself, you must callgzochi:remove-record!.
Many of the operations provided by (gzochi data) are
supported only for managed records. For example, you cannot use
gzochi:set-binding! to store a primitive value; you must
first “wrap” that value as a field in a managed record type that
includes information about how it should be serialized. In lieu of
creating distinct managed record types to wrap every unmanaged type
that needs to be stored, the procedures below are provided to
support the use of the generic gzochi:managed-serializable
type that encapsulates the serialization information for unmanaged
types.
Constructs a new
gzochi:managed-serializableobject with the specified value. The serializer-callback and deserializer-callback arguments must begzochi:callbackinstances specifying procedures to be used or serialization and deserialization, respectively.
Returns
#tif obj is a managed serializable record,#fotherwise.
Returns the value wrapped by the managed serializable record ms.
Compound data types such as vectors and hash tables are necessary components of any non-trivial application, but designing structures that support highly concurrent access to and modification of their contents is challenging. The following API describes “managed” implementations of R6RS vectors and hash tables, which partition their elements such that conflicts between transactions accessing different elements of the same container are minimized.
Returns a newly allocated managed vector of len elements. The initial contents of each position is set to
#f.
Returns a newly allocated managed vector composed of the given arguments. If any vector element is not a managed record, the keyword arguments #:serializer and #:deserializer must be given (in the form of
gzochi:callbackrecords), and managed serializable wrappers will be generated to hold any unmanaged elements.
Returns the contents of position k of vec. k must be a valid index of vec.
Stores obj at position k of vec. k must be a valid index of vec. The value returned by
gzochi:managed-vector-set!is unspecified. If obj is not a managed record, the keyword arguments #:serializer and #:deserializer must be given (in the form ofgzochi:callbackrecords), and a managed serializable wrapper will be generated to hold obj.
Returns the number of elements in vector as an exact integer.
Return a newly allocated list composed of the contents of v.
Constructs a new hash table that uses the procedure specified by the
gzochi:callbackarguments equiv-callback to compare keys and hash-callback as a hash function. equiv-callback must specify a procedure that accepts two arguments and returns a true value if the are equivalent,#fotherwise, hash-callback a procedure that accepts one argument and returns a non-negative integer.
Returns
#tif obj is a managed hash table,#fotherwise.
Returns the number of keys currently in the managed hash table hashtable.
Returns the value associated with key in the the managed hash table hashtable or default if none is found.
Associates the key key wth the value obj in the managed hash table hashtable, and returns an unspecified value.
If key is not a managed record, the keyword arguments #:key-serializer and #:key-deserializer must be given (in the form of
gzochi:callbackrecords), and a managed serializable wrapper will be generated to hold key. Likewise, if obj is not a managed record, #:value-serializer and #:value-deserializer must be provided.
Removes any association found for the key key in the hash table hashtable, and returns an unspecified value.
Returns
#tif the managed hash table hashtable contains an association for the key key,#fotherwise.
Associates with key in the managed hash table hashtable the result of calling proc, which must be a procedure that takes one argument, on the value currently associated with key in hashtable—or on default if no such association exists.
If key is not a managed record, the keyword arguments #:key-serializer and #:key-deserializer must be given. If proc returns something that is not a managed record—or if default becomes the value of the association—then #:value-serializer and #:value-deserializer must be provided.
Removes all of the associations from the managed hash table hashtable.
Returns a managed vector of the keys with associations in the managed hash table hashtable, in an unspecified order.
Returns two values—a managed vector of the keys with associations in the managed hash table hashtable, and a managed vector of the values to which these keys are mapped, in corresponding but unspecified order.
Returns a
gzochi:callbackrecord that represents the equivalence predicate used by hashtable.
Returns a
gzochi:callbackrecord that represents the hash function used by hashtable
The (gzochi io) library exports structures and procedures
useful for building serializations, which are used by the data
management features of the gzochid container for storing and
retrieving application data. The serializations described below may
be used directly as field serializations for a managed record-type
descriptor or composed to form serializations for more complex
types.
A serialization is an R6RS record with fields for a serialization procedure and a deserialization procedure. Serialization procedures should take two arguments, an output port and the value to be serialized, and should write the serialized form of the value to the port as a sequence of bytes; deserialization procedures will be passed an input port and should read the bytes necessary to return a value of the required type.
No type or length information—or delimiters—other than what the serializers themselves add to the output will be persisted. In particular, deserializer procedures should take care not to read more bytes than necessary from the port, as doing so will disrupt the operation of subsequent deserializers.
The base serialization record-type, constructor, predicate, and field accessors.
A serialization that uses an efficient, variable-length encoding format to read and write integer values of arbitrary size.
A serialization that encodes boolean values as integers, with
1representingtrueand0representing false. Note that the deserializer procedure will treat any non-zero value as encodingtrue.
A serialization that reads and writes text strings using the UTF-8 encoding, with an integer prefix giving the number of characters in the original string.
A serialization that reads and writes symbols by converting them to and from strings and delegating to the procedures in
gzochi:string-serialization.
A serialization that reads and writes R6RS bytevectors as sequences of bytes with encoded integer prefixes giving the lengths of the original vectors.
Returns a new
gzochi:serializationrecord that can be used as a serialization for a list of arbitrary length in which every car of the list has its serialization performed by the serialization ser.
The (gzochi log) library provides procedures for
performing application-level message logging, at various levels
of priority. All of the procedures in this library do their
writes transactionally, which means that the messages will only
be persisted (to the console and/or a file on disk, depending
on configuration) if the current transaction commits.
These procedures interpret their “rest” arguments as values
with which to replace escapes in the message string. Formatting
and replacement is done according to the rules of Guile's
simple-format procedure.
Writes a transactional message at the priority level priority, a symbol that must be one of
err,warning,notice,info, anddebug.
Each of these convenience procedures delegates to
gzochi:log, passing a respective priority value.
The (gzochi task) library provides procedures for
creating and scheduling transactional tasks. Tasks are
gzochi:callback records, and represent blocks of code to be
executed on behalf of a game application. All tasks are executed in
a fully transactional context, meaning that their side effects enjoy
guarantees of atomicity.
Transactionally schedules the
gzochi:callbackcallback for future execution. If delay is specified, it must be a positive integer giving the number of milliseconsd by which the execution of callback should be delayed. If delay is omitted, the behavior of this procedure is as if delay were zero: callback will be eligible for exeuction immediately upon the successful commit of the current transaction.Note that the execution delay of a scheduled task is “best effort.” The task will not be eligible for execution until at least the specified number of milliseconds have elapsed, but may be delayed further depending on the current state of the server.
Transactionally schedules the
gzochi:callbackcallback for periodic execution. period is the number of milliseconds that must elapse between executions of callback, and must be a positive integer. If delay is given, it must also be a positive integer, and specifies the desired delay before the first execution of the task.This procedure returns a “perodic task handle,” an opaque managed record that can be used to control the scheduling behavior of the resulting periodic task.
Returns
#tif obj is a periodic task handle,#fotherwise.
Cancels the periodic task associated with the periodic task handle handle. Note that depending on the state of the container's task execution schedule, the task may still be eligible for execution for a short period of time following its cancellation.
After this procedure returns, handle will be removed from the data store.
The (gzochi) library is a composite of all of the other
public gzochi libraries, with the exception of `(gzochi admin)'. It
imports and re-exports all of their exported procedures and syntactic
forms.
The following sample code is a complete gzochid application that implements a simple “Hello, world!” behavior. Authenticated clients receive a simple greeting and may send a single message to the server before being disconnected.
#!r6rs
(library (gzochi example hello-world)
(export initialize-hello-world
hello-client
client-message
client-disconnected)
(import (gzochi) (rnrs))
(define (initialize-hello-world properties)
(gzochi:notice "Hello, world!"))
(define (hello-client session)
(gzochi:client-session-send session
(string->utf8
(string-append "Hello, " (gzochi:client-session-name session) "!")))
(gzochi:make-client-session-listener
(gzochi:make-callback 'client-message '(gzochi example hello-world))
(gzochi:make-callback 'client-disconnected
'(gzochi example hello-world))))
(define (client-message session msg)
(let ((name (gzochi:client-session-name session)))
(gzochi:notice "~a: ~a" name (utf8->string msg))
(gzochi:client-session-send session
(string->utf8 (simple-format "Goodbye, ~a!" name))))
(gzochi:disconnect session))
(define (client-disconnected session) (if #f #f))
)
To launch this application, copy and paste the code above into a file named “hello-world.scm” and copy it to a sub-directory named “hello-world/gzochi/example” below your gzochid application deployment root directory. For example, the default deployment root is “/var/gzochid/deploy,” so the full path in the default case would be “/var/gzochid/deploy/hello-world/gzochi/example/hello-world.scm.” You'll also need to copy and paste the following game descriptor XML to a file named “game.xml” in the top-level “hello-world” directory.
<?xml version="1.0"?>
<game name="hello-world">
<description>Hello, world!</description>
<load-paths />
<initialized>
<callback module="gzochi example hello-world"
procedure="initialize-hello-world" />
</initialized>
<logged-in>
<callback module="gzochi example hello-world"
procedure="hello-client" />
</logged-in>
</game>
The descriptor begins by giving the application's short name and a
description. The load-paths element is a list of additional
locations the system should look for Scheme modules when module
dependencies are being resolved. The application's deployment
directory is implicitly on the load path, so this element is empty
in the descriptor for “hello-world.”
Next there are declarations for the two primary callbacks,
initialization and client connection. This game descriptor file sets
the initialization callback to the initialize-hello-world
procedure in the module (gzochi example hello-world) and sets
the connection callback to the procedure hello-client in that
same module.
The Scheme implementation of initialize-hello-world gets
passed a hash table with the game properties (which will be empty in
this case) and doesn't do anything except log a message. The
hello-client callback is a bit more interesting—it sends a
greeting to the newly-connected session and then constructs and
returns a new client session listener, which includes two additional
callbacks that will be used to handle events related specifically to
the new session. The first listener callback will be called when a
message is received from a client session; in this case, the
client-message procedure is used. The other callback
(client-disconneted in the example above) will be called when
the session disconnects.
Copyright © 2000,2001,2002 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.
Examples of suitable formats for Transparent copies include plain ascii without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.
The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.
A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.
You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation.
To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:
Copyright (C) year your name.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled ``GNU
Free Documentation License''.
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with...Texts.” line with this:
with the Invariant Sections being list their titles, with
the Front-Cover Texts being list, and with the Back-Cover Texts
being list.
If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.
If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
&gzochi:name-exists: gzochi conditions&gzochi:name-not-bound: gzochi conditions&gzochi:no-current-application: gzochi conditions&gzochi:object-removed: gzochi conditions&gzochi:transaction-aborted: gzochi conditions&gzochi:transaction-retry: gzochi conditions&gzochi:transaction-timeout: gzochi conditionsgzochi:application-context-name: gzochi admingzochi:application-context?: gzochi admingzochi:applications: gzochi admingzochi:bytevector-serialization: gzochi iogzochi:callback-data: gzochi appgzochi:callback-module: gzochi appgzochi:callback-procedure: gzochi appgzochi:callback?: gzochi appgzochi:cancel-periodic-task: gzochi taskgzochi:channel-name: gzochi channelgzochi:channel?: gzochi channelgzochi:client-session-listener: gzochi clientgzochi:client-session-listener-disconnected: gzochi clientgzochi:client-session-listener-received-message: gzochi clientgzochi:client-session-listener?: gzochi clientgzochi:client-session-name: gzochi clientgzochi:client-session?: gzochi clientgzochi:close-channel: gzochi channelgzochi:create-channel: gzochi channelgzochi:current-application: gzochi admingzochi:define-managed-record-type: gzochi datagzochi:get-binding: gzochi datagzochi:get-channel: gzochi channelgzochi:join-channel: gzochi channelgzochi:leave-channel: gzochi channelgzochi:log: gzochi loggzochi:log-debug: gzochi loggzochi:log-err: gzochi loggzochi:log-info: gzochi loggzochi:log-notice: gzochi loggzochi:log-warning: gzochi loggzochi:make-callback: gzochi appgzochi:make-client-session-listener: gzochi clientgzochi:make-managed-hashtable: gzochi datagzochi:make-managed-record-type-descriptor: gzochi datagzochi:make-managed-serializable: gzochi datagzochi:make-managed-vector: gzochi datagzochi:make-name-exists-condition: gzochi conditionsgzochi:make-name-not-bound-condition: gzochi conditionsgzochi:make-no-current-application-condition: gzochi conditionsgzochi:make-object-removed-condition: gzochi conditionsgzochi:make-serialization: gzochi iogzochi:make-transaction-aborted-condition: gzochi conditionsgzochi:make-transaction-retry-condition: gzochi conditionsgzochi:make-transaction-timeout-condition: gzochi conditionsgzochi:make-uniform-list-serialization: gzochi iogzochi:managed-hashtable-clear!: gzochi datagzochi:managed-hashtable-contains?: gzochi datagzochi:managed-hashtable-delete!: gzochi datagzochi:managed-hashtable-entries: gzochi datagzochi:managed-hashtable-equivalence-function: gzochi datagzochi:managed-hashtable-hash-function: gzochi datagzochi:managed-hashtable-keys: gzochi datagzochi:managed-hashtable-ref: gzochi datagzochi:managed-hashtable-set!: gzochi datagzochi:managed-hashtable-size: gzochi datagzochi:managed-hashtable-update!: gzochi datagzochi:managed-hashtable?: gzochi datagzochi:managed-record-accessor: gzochi datagzochi:managed-record-constructor: gzochi datagzochi:managed-record-constructor-descriptor: gzochi datagzochi:managed-record-mutator: gzochi datagzochi:managed-record-predicate: gzochi datagzochi:managed-record-rtd: gzochi datagzochi:managed-record-type-descriptor: gzochi datagzochi:managed-record-type-name: gzochi datagzochi:managed-record-type-parent: gzochi datagzochi:managed-record-type-uid: gzochi datagzochi:managed-serializable-value: gzochi datagzochi:managed-serializable?: gzochi datagzochi:managed-vector: gzochi datagzochi:managed-vector->list: gzochi datagzochi:managed-vector-length: gzochi datagzochi:managed-vector-ref: gzochi datagzochi:managed-vector-set!: gzochi datagzochi:managed-vector?: gzochi datagzochi:name-exists-condition-name: gzochi conditionsgzochi:name-exists-condition?: gzochi conditionsgzochi:name-not-bound-condition-name: gzochi conditionsgzochi:name-not-bound-condition?: gzochi conditionsgzochi:no-current-application-condition?: gzochi conditionsgzochi:object-removed-condition?: gzochi conditionsgzochi:periodic-task-handle?: gzochi taskgzochi:read-boolean: gzochi iogzochi:read-bytevector: gzochi iogzochi:read-integer: gzochi iogzochi:read-string: gzochi iogzochi:read-symbol: gzochi iogzochi:remove-binding!: gzochi datagzochi:schedule-periodic-task: gzochi taskgzochi:schedule-task: gzochi taskgzochi:send-channel-message: gzochi channelgzochi:send-message: gzochi clientgzochi:serialization-deserializer: gzochi iogzochi:serialization-serializer: gzochi iogzochi:serialization?: gzochi iogzochi:set-binding!: gzochi datagzochi:symbol-serialization: gzochi iogzochi:transaction-aborted-condition?: gzochi conditionsgzochi:transaction-retry-condition?: gzochi conditionsgzochi:transaction-timeout-condition?: gzochi conditionsgzochi:with-application: gzochi admingzochi:write-boolean: gzochi iogzochi:write-bytevector: gzochi iogzochi:write-integer: gzochi iogzochi:write-string: gzochi iogzochi:write-symbol: gzochi io