Răsfoiți Sursa

added single-header generator script, some cleanup

Vladislav Gritsenko 6 ani în urmă
părinte
comite
d42061f58f
15 a modificat fișierele cu 6656 adăugiri și 2871 ștergeri
  1. 2 0
      .gitignore
  2. 0 2303
      Doxyfile
  3. 0 191
      DoxygenLayout.xml
  4. 0 27
      Makefile.am
  5. 0 28
      configure.ac
  6. 0 168
      enet.dsp
  7. 0 86
      enet_dll.cbp
  8. 6462 0
      include/enet.h
  9. 2 0
      include/enet/enet.h
  10. 0 10
      libenet.pc.in
  11. 0 0
      m4/.keep
  12. 0 0
      misc/ChangeLog
  13. 124 0
      misc/build-singleheader.js
  14. 57 58
      premake4.lua
  15. 9 0
      test/build.c

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+build/
+.DS_store

+ 0 - 2303
Doxyfile

@@ -1,2303 +0,0 @@
-# Doxyfile 1.8.6
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME           = "ENet"
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER         = v1.3.13
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF          = "Reliable UDP networking library"
-
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
-# the documentation. The maximum height of the logo should not exceed 55 pixels
-# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
-# to the output directory.
-
-PROJECT_LOGO           = 
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       = docs
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS         = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF       =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC    = YES
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB  = YES
-
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES        = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH        = 
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH    =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF      = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF           = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
-# new page for each member. If set to NO, the documentation of a member will be
-# part of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE               = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
-
-ALIASES                =
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST              =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C  = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C.
-#
-# Note For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING      =
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT       = YES
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT       = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT    = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT        = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC   = YES
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING            = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = YES
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS  = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT   = YES
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE      = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL            = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC         = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES  = NO
-
-# This flag is only useful for Objective-C code. When set to YES local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS     = YES
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO these classes will be included in the various overviews. This option has
-# no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES     = YES
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES       = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES       = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC  = YES
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES   = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS        = YES
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = YES
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES       = YES
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME     = YES
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING  = NO
-
-# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
-# todo list. This list is created by putting \todo commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
-# test list. This list is created by putting \test commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS       =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES the list
-# will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES        = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER    =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE            = DoxygenLayout.xml
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. Do not use file names with spaces, bibtex cannot handle them. See
-# also \cite for info how to create references.
-
-CITE_BIB_FILES         =
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS               = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO doxygen will only warn about wrong or incomplete parameter
-# documentation, but not about the absence of documentation.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC       = YES
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE           =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
-# Note: If this tag is empty the current directory is searched.
-
-INPUT                  =
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
-
-FILE_PATTERNS          = *.c *.h *.dox
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE              = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE                =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS        =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH           =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS       =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH             = ${CMAKE_CURRENT_SOURCE_DIR}
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-
-INPUT_FILTER           =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS        =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER ) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES    = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER         = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS    = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION    = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = NO
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS        = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS       = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX     = YES
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX    = 1
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX          =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER            =
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER            =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET        =
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
-# defined cascading style sheet that is included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
-# Doxygen will copy the style sheet file to the output directory. For an example
-# see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET  =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES       =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the stylesheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE    = 118
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT    = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA  = 240
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP         = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 0
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET        = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID       = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME  = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP      = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE               =
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler ( hhc.exe). If non-empty
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION           =
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated (
-# YES) or that it should be included in the master .chm file ( NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI           = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING     =
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated (
-# YES) or a normal table of contents ( NO) in the .chm file.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND             = YES
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP           = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE               =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE          = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER     = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME   =
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS  =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS  =
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION           =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP   = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID         = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX          = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW      = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE   = 1
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH         = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW    = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE       = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT    = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using prerendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX            = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT         = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS     =
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE       =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE           = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavours of web server based searching depending on the
-# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
-# searching and an index file used by the script. When EXTERNAL_SEARCH is
-# enabled the indexing and searching needs to be provided by external tools. See
-# the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH    = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH        = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL       =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE        = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID     =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS  =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX         = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE             = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES         =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
-# replace them by respectively the title of the page, the current date and time,
-# only the current date, the version number of doxygen, the project name (see
-# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER           =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER           =
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES      =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS         = YES
-
-# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE        = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES     = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE      = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE        = plain
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE    =
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE    =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION          = .3
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT             = xml
-
-# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
-# validating XML parser to check the syntax of the XML files.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_SCHEMA             =
-
-# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
-# validating XML parser to check the syntax of the XML files.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_DTD                =
-
-# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK       = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT         = docbook
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
-# Definitions (see http://autogen.sf.net) file that captures the structure of
-# the code including all documentation. Note that this feature is still
-# experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
-# in the source code. If set to NO only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION        = YES
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF     = NO
-
-# If the SEARCH_INCLUDES tag is set to YES the includes files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH           =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS  =
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED             = ENET_CALLBACK= ENET_API=
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro defi ENET_CALLBACK=nition that overrules the
-# definition found in the source  ENET_CALLBACK=code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED      =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all refrences to function-like macros that are alone on a line, have an
-# all uppercase name, and do not end with a semicolon. Such function macros are
-# typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have an unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES               =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE       =
-
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
-# class index. If set to NO only the inherited external classes will be listed.
-# The default value is: NO.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
-# the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS        = YES
-
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES         = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS         = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH            =
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH               =
-
-# If set to YES, the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS   = NO
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: NO.
-
-HAVE_DOT               = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS        = 0
-
-# When you want a differently looking font n the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME           = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE           = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH           =
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH    = YES
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK               = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS   = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH          = YES
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH             = NO
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH           = NO
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, jpg, gif and svg.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT       = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG        = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH               =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS           =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS           =
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS           =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS      = YES
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP            = YES

+ 0 - 191
DoxygenLayout.xml

@@ -1,191 +0,0 @@
-<doxygenlayout version="1.0">
-  <!-- Generated by doxygen 1.8.6 -->
-  <!-- Navigation index tabs for HTML output -->
-  <navindex>
-    <tab type="mainpage" visible="yes" title="Home"/>
-    <tab type="user" visible="yes" title="Features" url="@ref Features" />
-    <tab type="user" visible="yes" title="Downloads" url="@ref Downloads" />
-    <tab type="user" visible="yes" title="Installation" url="@ref Installation" />
-    <tab type="user" visible="yes" title="Tutorial" url="@ref Tutorial" />
-    <tab type="user" visible="yes" title="Mailing List" url="@ref MailingList" />
-    <tab type="user" visible="yes" title="IRC Channel" url="@ref IRCChannel" />
-    <tab type="user" visible="yes" title="FAQ" url="@ref FAQ" />
-    <tab type="user" visible="yes" title="License" url="@ref License" />
-    <tab type="usergroup" visible="yes" title="Documentation" briefdescription="Documentation">
-        <tab type="modules" visible="yes" title="Functions" intro=""/>
-        <tab type="classlist" visible="yes" title="Data Structures" intro=""/>
-        <tab type="filelist" visible="yes" title="Files" intro=""/>
-        <tab type="globals" visible="yes" title="" intro=""/>
-    </tab>
-  </navindex>
-
-  <!-- Layout definition for a class page -->
-  <class>
-    <briefdescription visible="yes"/>
-    <includes visible="$SHOW_INCLUDE_FILES"/>
-    <inheritancegraph visible="$CLASS_GRAPH"/>
-    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
-    <memberdecl>
-      <nestedclasses visible="yes" title=""/>
-      <publictypes title=""/>
-      <services title=""/>
-      <interfaces title=""/>
-      <publicslots title=""/>
-      <signals title=""/>
-      <publicmethods title=""/>
-      <publicstaticmethods title=""/>
-      <publicattributes title=""/>
-      <publicstaticattributes title=""/>
-      <protectedtypes title=""/>
-      <protectedslots title=""/>
-      <protectedmethods title=""/>
-      <protectedstaticmethods title=""/>
-      <protectedattributes title=""/>
-      <protectedstaticattributes title=""/>
-      <packagetypes title=""/>
-      <packagemethods title=""/>
-      <packagestaticmethods title=""/>
-      <packageattributes title=""/>
-      <packagestaticattributes title=""/>
-      <properties title=""/>
-      <events title=""/>
-      <privatetypes title=""/>
-      <privateslots title=""/>
-      <privatemethods title=""/>
-      <privatestaticmethods title=""/>
-      <privateattributes title=""/>
-      <privatestaticattributes title=""/>
-      <friends title=""/>
-      <related title="" subtitle=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <inlineclasses title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <services title=""/>
-      <interfaces title=""/>
-      <constructors title=""/>
-      <functions title=""/>
-      <related title=""/>
-      <variables title=""/>
-      <properties title=""/>
-      <events title=""/>
-    </memberdef>
-    <allmemberslink visible="yes"/>
-    <usedfiles visible="$SHOW_USED_FILES"/>
-    <authorsection visible="yes"/>
-  </class>
-
-  <!-- Layout definition for a namespace page -->
-  <namespace>
-    <briefdescription visible="yes"/>
-    <memberdecl>
-      <nestednamespaces visible="yes" title=""/>
-      <constantgroups visible="yes" title=""/>
-      <classes visible="yes" title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <inlineclasses title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-    </memberdef>
-    <authorsection visible="yes"/>
-  </namespace>
-
-  <!-- Layout definition for a file page -->
-  <file>
-    <briefdescription visible="yes"/>
-    <includes visible="$SHOW_INCLUDE_FILES"/>
-    <includegraph visible="$INCLUDE_GRAPH"/>
-    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
-    <sourcelink visible="yes"/>
-    <memberdecl>
-      <classes visible="yes" title=""/>
-      <namespaces visible="yes" title=""/>
-      <constantgroups visible="yes" title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <inlineclasses title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-    </memberdef>
-    <authorsection/>
-  </file>
-
-  <!-- Layout definition for a group page -->
-  <group>
-    <briefdescription visible="yes"/>
-    <groupgraph visible="$GROUP_GRAPHS"/>
-    <memberdecl>
-      <nestedgroups visible="yes" title=""/>
-      <dirs visible="yes" title=""/>
-      <files visible="yes" title=""/>
-      <namespaces visible="yes" title=""/>
-      <classes visible="yes" title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <enumvalues title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <signals title=""/>
-      <publicslots title=""/>
-      <protectedslots title=""/>
-      <privateslots title=""/>
-      <events title=""/>
-      <properties title=""/>
-      <friends title=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <pagedocs/>
-      <inlineclasses title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <enumvalues title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <signals title=""/>
-      <publicslots title=""/>
-      <protectedslots title=""/>
-      <privateslots title=""/>
-      <events title=""/>
-      <properties title=""/>
-      <friends title=""/>
-    </memberdef>
-    <authorsection visible="yes"/>
-  </group>
-
-  <!-- Layout definition for a directory page -->
-  <directory>
-    <briefdescription visible="yes"/>
-    <directorygraph visible="yes"/>
-    <memberdecl>
-      <dirs visible="yes"/>
-      <files visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-  </directory>
-</doxygenlayout>

+ 0 - 27
Makefile.am

@@ -1,27 +0,0 @@
-pkgconfigdir = $(libdir)/pkgconfig
-nodist_pkgconfig_DATA = libenet.pc
-
-enetincludedir=$(includedir)/enet
-enetinclude_HEADERS = \
-	include/enet/callbacks.h \
-	include/enet/enet.h \
-	include/enet/list.h \
-	include/enet/protocol.h \
-	include/enet/time.h \
-	include/enet/types.h \
-	include/enet/unix.h \
-	include/enet/utility.h \
-	include/enet/win32.h
-
-lib_LTLIBRARIES = libenet.la
-libenet_la_SOURCES = callbacks.c compress.c host.c list.c packet.c peer.c protocol.c unix.c win32.c
-# see info '(libtool) Updating version info' before making a release
-VERSIONINFO = -version-info 7:1:0
-if MINGW
-libenet_la_LDFLAGS = -no-undefined -lwinmm -lws2_32 $(AM_LDFLAGS) $(VERSIONINFO)
-else
-libenet_la_LDFLAGS = $(AM_LDFLAGS) $(VERSIONINFO)
-endif
-AM_CPPFLAGS = -I$(top_srcdir)/include
-
-ACLOCAL_AMFLAGS = -Im4

+ 0 - 28
configure.ac

@@ -1,28 +0,0 @@
-AC_INIT([libenet], [1.3.13])
-AC_CONFIG_SRCDIR([include/enet/enet.h])
-AM_INIT_AUTOMAKE([foreign])
-
-AC_CONFIG_MACRO_DIR([m4])
-
-AC_PROG_CC
-AC_PROG_LIBTOOL
-
-AC_CHECK_FUNC(getaddrinfo, [AC_DEFINE(HAS_GETADDRINFO)])
-AC_CHECK_FUNC(getnameinfo, [AC_DEFINE(HAS_GETNAMEINFO)])
-AC_CHECK_FUNC(gethostbyaddr_r, [AC_DEFINE(HAS_GETHOSTBYADDR_R)])
-AC_CHECK_FUNC(gethostbyname_r, [AC_DEFINE(HAS_GETHOSTBYNAME_R)])
-AC_CHECK_FUNC(poll, [AC_DEFINE(HAS_POLL)])
-AC_CHECK_FUNC(fcntl, [AC_DEFINE(HAS_FCNTL)])
-AC_CHECK_FUNC(inet_pton, [AC_DEFINE(HAS_INET_PTON)])
-AC_CHECK_FUNC(inet_ntop, [AC_DEFINE(HAS_INET_NTOP)])
-
-AC_CHECK_MEMBER(struct msghdr.msg_flags, [AC_DEFINE(HAS_MSGHDR_FLAGS)], , [#include <sys/socket.h>])
-
-AC_CHECK_TYPE(socklen_t, [AC_DEFINE(HAS_SOCKLEN_T)], , 
-              #include <sys/types.h>
-              #include <sys/socket.h>
-)
-
-AC_CONFIG_FILES([Makefile
-	libenet.pc])
-AC_OUTPUT

+ 0 - 168
enet.dsp

@@ -1,168 +0,0 @@
-# Microsoft Developer Studio Project File - Name="enet" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Static Library" 0x0104
-
-CFG=enet - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE 
-!MESSAGE NMAKE /f "enet.mak".
-!MESSAGE 
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE 
-!MESSAGE NMAKE /f "enet.mak" CFG="enet - Win32 Debug"
-!MESSAGE 
-!MESSAGE Possible choices for configuration are:
-!MESSAGE 
-!MESSAGE "enet - Win32 Release" (based on "Win32 (x86) Static Library")
-!MESSAGE "enet - Win32 Debug" (based on "Win32 (x86) Static Library")
-!MESSAGE 
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF  "$(CFG)" == "enet - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Target_Dir ""
-MTL=midl.exe
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD CPP /nologo /W3 /O2 /I "include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ELSEIF  "$(CFG)" == "enet - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Target_Dir ""
-MTL=midl.exe
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
-# ADD CPP /nologo /G6 /MTd /W3 /ZI /Od /I "include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ENDIF 
-
-# Begin Target
-
-# Name "enet - Win32 Release"
-# Name "enet - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\host.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\list.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\callbacks.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\compress.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\packet.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\peer.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\protocol.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\unix.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\win32.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\include\enet\enet.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\include\enet\list.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\include\enet\callbacks.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\include\enet\protocol.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\include\enet\time.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\include\enet\types.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\include\enet\unix.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\include\enet\utility.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\include\enet\win32.h
-# End Source File
-# End Group
-# End Target
-# End Project

+ 0 - 86
enet_dll.cbp

@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<CodeBlocks_project_file>
-	<FileVersion major="1" minor="6" />
-	<Project>
-		<Option title="enet_dll" />
-		<Option pch_mode="2" />
-		<Option compiler="gcc" />
-		<Build>
-			<Target title="Debug">
-				<Option output="bin\Debug\libenet" prefix_auto="1" extension_auto="1" />
-				<Option object_output="obj\Debug\" />
-				<Option type="3" />
-				<Option compiler="gcc" />
-				<Option createDefFile="1" />
-				<Option createStaticLib="1" />
-				<Compiler>
-					<Add option="-g" />
-				</Compiler>
-			</Target>
-			<Target title="Release">
-				<Option output="bin\Release\libenet" prefix_auto="1" extension_auto="1" />
-				<Option object_output="obj\Release\" />
-				<Option type="3" />
-				<Option compiler="gcc" />
-				<Option createDefFile="1" />
-				<Option createStaticLib="1" />
-				<Compiler>
-					<Add option="-O2" />
-				</Compiler>
-				<Linker>
-					<Add option="-s" />
-				</Linker>
-			</Target>
-		</Build>
-		<Compiler>
-			<Add option="-Wall" />
-			<Add option="-DENET_DLL" />
-			<Add directory="include" />
-		</Compiler>
-		<Linker>
-			<Add library="ws2_32" />
-			<Add library="Winmm" />
-		</Linker>
-		<Unit filename="callbacks.c">
-			<Option compilerVar="CC" />
-		</Unit>
-		<Unit filename="compress.c">
-			<Option compilerVar="CC" />
-		</Unit>
-		<Unit filename="host.c">
-			<Option compilerVar="CC" />
-		</Unit>
-		<Unit filename="include\enet\callbacks.h" />
-		<Unit filename="include\enet\enet.h" />
-		<Unit filename="include\enet\list.h" />
-		<Unit filename="include\enet\protocol.h" />
-		<Unit filename="include\enet\time.h" />
-		<Unit filename="include\enet\types.h" />
-		<Unit filename="include\enet\unix.h" />
-		<Unit filename="include\enet\utility.h" />
-		<Unit filename="include\enet\win32.h" />
-		<Unit filename="list.c">
-			<Option compilerVar="CC" />
-		</Unit>
-		<Unit filename="packet.c">
-			<Option compilerVar="CC" />
-		</Unit>
-		<Unit filename="peer.c">
-			<Option compilerVar="CC" />
-		</Unit>
-		<Unit filename="protocol.c">
-			<Option compilerVar="CC" />
-		</Unit>
-		<Unit filename="unix.c">
-			<Option compilerVar="CC" />
-		</Unit>
-		<Unit filename="win32.c">
-			<Option compilerVar="CC" />
-		</Unit>
-		<Extensions>
-			<code_completion />
-			<envvars />
-			<debugger />
-		</Extensions>
-	</Project>
-</CodeBlocks_project_file>

+ 6462 - 0
include/enet.h

@@ -0,0 +1,6462 @@
+/**
+ * includes/enet.h - a Single-Header auto-generated variant of enet.h library.
+ *
+ * Usage:
+ * #define ENET_IMPLEMENTATION exactly in ONE source file right BEFORE including the library, like:
+ *
+ * #define ENET_IMPLEMENTATION
+ * #include <enet.h>
+ *
+ */
+
+/**
+ @file  enet.h
+ @brief ENet public header file
+*/
+#ifndef __ENET_ENET_H__
+#define __ENET_ENET_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+
+#ifdef _WIN32
+/**
+ @file  win32.h
+ @brief ENet Win32 header
+*/
+#ifndef __ENET_WIN32_H__
+#define __ENET_WIN32_H__
+
+#ifdef _MSC_VER
+#ifdef ENET_BUILDING_LIB
+#pragma warning (disable: 4267) // size_t to int conversion
+#pragma warning (disable: 4244) // 64bit to 32bit int
+#pragma warning (disable: 4018) // signed/unsigned mismatch
+#pragma warning (disable: 4146) // unary minus operator applied to unsigned type
+#endif
+#endif
+
+
+#include <winsock2.h>
+
+typedef SOCKET ENetSocket;
+
+#define ENET_SOCKET_NULL INVALID_SOCKET
+
+#define ENET_HOST_TO_NET_16(value) (htons (value))
+#define ENET_HOST_TO_NET_32(value) (htonl (value))
+
+#define ENET_NET_TO_HOST_16(value) (ntohs (value))
+#define ENET_NET_TO_HOST_32(value) (ntohl (value))
+
+typedef struct
+{
+    size_t dataLength;
+    void * data;
+} ENetBuffer;
+
+#define ENET_CALLBACK __cdecl
+
+#ifdef ENET_DLL
+#ifdef ENET_BUILDING_LIB
+#define ENET_API __declspec( dllexport )
+#else
+#define ENET_API __declspec( dllimport )
+#endif /* ENET_BUILDING_LIB */
+#else /* !ENET_DLL */
+#define ENET_API extern
+#endif /* ENET_DLL */
+
+typedef fd_set ENetSocketSet;
+
+#define ENET_SOCKETSET_EMPTY(sockset)          FD_ZERO (& (sockset))
+#define ENET_SOCKETSET_ADD(sockset, socket)    FD_SET (socket, & (sockset))
+#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset))
+#define ENET_SOCKETSET_CHECK(sockset, socket)  FD_ISSET (socket, & (sockset))
+
+#endif /* __ENET_WIN32_H__ */
+#else
+/**
+ @file  unix.h
+ @brief ENet Unix header
+*/
+#ifndef __ENET_UNIX_H__
+#define __ENET_UNIX_H__
+
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#ifdef MSG_MAXIOVLEN
+#define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN
+#endif
+
+typedef int ENetSocket;
+
+#define ENET_SOCKET_NULL -1
+
+#define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */
+#define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */
+
+#define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */
+#define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */
+
+typedef struct
+{
+    void * data;
+    size_t dataLength;
+} ENetBuffer;
+
+#define ENET_CALLBACK
+
+#define ENET_API extern
+
+typedef fd_set ENetSocketSet;
+
+#define ENET_SOCKETSET_EMPTY(sockset)          FD_ZERO (& (sockset))
+#define ENET_SOCKETSET_ADD(sockset, socket)    FD_SET (socket, & (sockset))
+#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset))
+#define ENET_SOCKETSET_CHECK(sockset, socket)  FD_ISSET (socket, & (sockset))
+
+#endif /* __ENET_UNIX_H__ */
+#endif
+
+/**
+ @file  types.h
+ @brief type definitions for ENet
+*/
+#ifndef __ENET_TYPES_H__
+#define __ENET_TYPES_H__
+
+#include <stdint.h>
+
+typedef unsigned char enet_uint8;       /**< unsigned 8-bit type  */
+typedef unsigned short enet_uint16;     /**< unsigned 16-bit type */
+typedef unsigned int enet_uint32;      /**< unsigned 32-bit type */
+typedef uint64_t enet_uint64;
+
+#endif /* __ENET_TYPES_H__ */
+/**
+ @file  protocol.h
+ @brief ENet protocol
+*/
+#ifndef __ENET_PROTOCOL_H__
+#define __ENET_PROTOCOL_H__
+
+
+
+enum
+{
+   ENET_PROTOCOL_MINIMUM_MTU             = 576,
+   ENET_PROTOCOL_MAXIMUM_MTU             = 4096,
+   ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32,
+   ENET_PROTOCOL_MINIMUM_WINDOW_SIZE     = 4096,
+   ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE     = 65536,
+   ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT   = 1,
+   ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT   = 255,
+   ENET_PROTOCOL_MAXIMUM_PEER_ID         = 0xFFF,
+   ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT  = 1024 * 1024
+};
+
+typedef enum _ENetProtocolCommand
+{
+   ENET_PROTOCOL_COMMAND_NONE               = 0,
+   ENET_PROTOCOL_COMMAND_ACKNOWLEDGE        = 1,
+   ENET_PROTOCOL_COMMAND_CONNECT            = 2,
+   ENET_PROTOCOL_COMMAND_VERIFY_CONNECT     = 3,
+   ENET_PROTOCOL_COMMAND_DISCONNECT         = 4,
+   ENET_PROTOCOL_COMMAND_PING               = 5,
+   ENET_PROTOCOL_COMMAND_SEND_RELIABLE      = 6,
+   ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE    = 7,
+   ENET_PROTOCOL_COMMAND_SEND_FRAGMENT      = 8,
+   ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED   = 9,
+   ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT    = 10,
+   ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11,
+   ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12,
+   ENET_PROTOCOL_COMMAND_COUNT              = 13,
+
+   ENET_PROTOCOL_COMMAND_MASK               = 0x0F
+} ENetProtocolCommand;
+
+typedef enum _ENetProtocolFlag
+{
+   ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7),
+   ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6),
+
+   ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14),
+   ENET_PROTOCOL_HEADER_FLAG_SENT_TIME  = (1 << 15),
+   ENET_PROTOCOL_HEADER_FLAG_MASK       = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME,
+
+   ENET_PROTOCOL_HEADER_SESSION_MASK    = (3 << 12),
+   ENET_PROTOCOL_HEADER_SESSION_SHIFT   = 12
+} ENetProtocolFlag;
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#define ENET_PACKED
+#elif defined(__GNUC__) || defined(__clang__)
+#define ENET_PACKED __attribute__ ((packed))
+#else
+#define ENET_PACKED
+#endif
+
+typedef struct _ENetProtocolHeader
+{
+   enet_uint16 peerID;
+   enet_uint16 sentTime;
+} ENET_PACKED ENetProtocolHeader;
+
+typedef struct _ENetProtocolCommandHeader
+{
+   enet_uint8 command;
+   enet_uint8 channelID;
+   enet_uint16 reliableSequenceNumber;
+} ENET_PACKED ENetProtocolCommandHeader;
+
+typedef struct _ENetProtocolAcknowledge
+{
+   ENetProtocolCommandHeader header;
+   enet_uint16 receivedReliableSequenceNumber;
+   enet_uint16 receivedSentTime;
+} ENET_PACKED ENetProtocolAcknowledge;
+
+typedef struct _ENetProtocolConnect
+{
+   ENetProtocolCommandHeader header;
+   enet_uint16 outgoingPeerID;
+   enet_uint8  incomingSessionID;
+   enet_uint8  outgoingSessionID;
+   enet_uint32 mtu;
+   enet_uint32 windowSize;
+   enet_uint32 channelCount;
+   enet_uint32 incomingBandwidth;
+   enet_uint32 outgoingBandwidth;
+   enet_uint32 packetThrottleInterval;
+   enet_uint32 packetThrottleAcceleration;
+   enet_uint32 packetThrottleDeceleration;
+   enet_uint32 connectID;
+   enet_uint32 data;
+} ENET_PACKED ENetProtocolConnect;
+
+typedef struct _ENetProtocolVerifyConnect
+{
+   ENetProtocolCommandHeader header;
+   enet_uint16 outgoingPeerID;
+   enet_uint8  incomingSessionID;
+   enet_uint8  outgoingSessionID;
+   enet_uint32 mtu;
+   enet_uint32 windowSize;
+   enet_uint32 channelCount;
+   enet_uint32 incomingBandwidth;
+   enet_uint32 outgoingBandwidth;
+   enet_uint32 packetThrottleInterval;
+   enet_uint32 packetThrottleAcceleration;
+   enet_uint32 packetThrottleDeceleration;
+   enet_uint32 connectID;
+} ENET_PACKED ENetProtocolVerifyConnect;
+
+typedef struct _ENetProtocolBandwidthLimit
+{
+   ENetProtocolCommandHeader header;
+   enet_uint32 incomingBandwidth;
+   enet_uint32 outgoingBandwidth;
+} ENET_PACKED ENetProtocolBandwidthLimit;
+
+typedef struct _ENetProtocolThrottleConfigure
+{
+   ENetProtocolCommandHeader header;
+   enet_uint32 packetThrottleInterval;
+   enet_uint32 packetThrottleAcceleration;
+   enet_uint32 packetThrottleDeceleration;
+} ENET_PACKED ENetProtocolThrottleConfigure;
+
+typedef struct _ENetProtocolDisconnect
+{
+   ENetProtocolCommandHeader header;
+   enet_uint32 data;
+} ENET_PACKED ENetProtocolDisconnect;
+
+typedef struct _ENetProtocolPing
+{
+   ENetProtocolCommandHeader header;
+} ENET_PACKED ENetProtocolPing;
+
+typedef struct _ENetProtocolSendReliable
+{
+   ENetProtocolCommandHeader header;
+   enet_uint16 dataLength;
+} ENET_PACKED ENetProtocolSendReliable;
+
+typedef struct _ENetProtocolSendUnreliable
+{
+   ENetProtocolCommandHeader header;
+   enet_uint16 unreliableSequenceNumber;
+   enet_uint16 dataLength;
+} ENET_PACKED ENetProtocolSendUnreliable;
+
+typedef struct _ENetProtocolSendUnsequenced
+{
+   ENetProtocolCommandHeader header;
+   enet_uint16 unsequencedGroup;
+   enet_uint16 dataLength;
+} ENET_PACKED ENetProtocolSendUnsequenced;
+
+typedef struct _ENetProtocolSendFragment
+{
+   ENetProtocolCommandHeader header;
+   enet_uint16 startSequenceNumber;
+   enet_uint16 dataLength;
+   enet_uint32 fragmentCount;
+   enet_uint32 fragmentNumber;
+   enet_uint32 totalLength;
+   enet_uint32 fragmentOffset;
+} ENET_PACKED ENetProtocolSendFragment;
+
+typedef union _ENetProtocol
+{
+   ENetProtocolCommandHeader header;
+   ENetProtocolAcknowledge acknowledge;
+   ENetProtocolConnect connect;
+   ENetProtocolVerifyConnect verifyConnect;
+   ENetProtocolDisconnect disconnect;
+   ENetProtocolPing ping;
+   ENetProtocolSendReliable sendReliable;
+   ENetProtocolSendUnreliable sendUnreliable;
+   ENetProtocolSendUnsequenced sendUnsequenced;
+   ENetProtocolSendFragment sendFragment;
+   ENetProtocolBandwidthLimit bandwidthLimit;
+   ENetProtocolThrottleConfigure throttleConfigure;
+} ENET_PACKED ENetProtocol;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif
+
+#endif /* __ENET_PROTOCOL_H__ */
+/**
+ @file  list.h
+ @brief ENet list management
+*/
+#ifndef __ENET_LIST_H__
+#define __ENET_LIST_H__
+
+
+
+typedef struct _ENetListNode
+{
+   struct _ENetListNode * next;
+   struct _ENetListNode * previous;
+} ENetListNode;
+
+typedef ENetListNode * ENetListIterator;
+
+typedef struct _ENetList
+{
+   ENetListNode sentinel;
+} ENetList;
+
+extern void enet_list_clear (ENetList *);
+
+extern ENetListIterator enet_list_insert (ENetListIterator, void *);
+extern void * enet_list_remove (ENetListIterator);
+extern ENetListIterator enet_list_move (ENetListIterator, void *, void *);
+
+extern size_t enet_list_size (ENetList *);
+
+#define enet_list_begin(list) ((list) -> sentinel.next)
+#define enet_list_end(list) (& (list) -> sentinel)
+
+#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list))
+
+#define enet_list_next(iterator) ((iterator) -> next)
+#define enet_list_previous(iterator) ((iterator) -> previous)
+
+#define enet_list_front(list) ((void *) (list) -> sentinel.next)
+#define enet_list_back(list) ((void *) (list) -> sentinel.previous)
+
+#endif /* __ENET_LIST_H__ */
+/**
+ @file  time.h
+ @brief ENet time constants and macros
+*/
+#ifndef __ENET_TIME_H__
+#define __ENET_TIME_H__
+
+#define ENET_TIME_OVERFLOW 86400000
+
+#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW)
+#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW)
+#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b))
+#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b))
+
+#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b))
+
+#endif /* __ENET_TIME_H__ */
+/**
+ @file  utility.h
+ @brief ENet utility header
+*/
+#ifndef __ENET_UTILITY_H__
+#define __ENET_UTILITY_H__
+
+#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y))
+#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#endif /* __ENET_UTILITY_H__ */
+/**
+ @file  callbacks.h
+ @brief ENet callbacks
+*/
+#ifndef __ENET_CALLBACKS_H__
+#define __ENET_CALLBACKS_H__
+
+
+
+typedef struct _ENetCallbacks
+{
+    void * (ENET_CALLBACK * malloc) (size_t size);
+    void (ENET_CALLBACK * free) (void * memory);
+    void (ENET_CALLBACK * no_memory) (void);
+} ENetCallbacks;
+
+/** @defgroup callbacks ENet internal callbacks
+    @{
+    @ingroup private
+*/
+extern void * enet_malloc (size_t);
+extern void   enet_free (void *);
+
+/** @} */
+
+#endif /* __ENET_CALLBACKS_H__ */
+
+#define ENET_VERSION_MAJOR 1
+#define ENET_VERSION_MINOR 3
+#define ENET_VERSION_PATCH 13
+#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch))
+#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF)
+#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF)
+#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF)
+#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH)
+
+typedef enet_uint32 ENetVersion;
+
+struct _ENetHost;
+struct _ENetEvent;
+struct _ENetPacket;
+
+typedef enum _ENetSocketType
+{
+   ENET_SOCKET_TYPE_STREAM   = 1,
+   ENET_SOCKET_TYPE_DATAGRAM = 2
+} ENetSocketType;
+
+typedef enum _ENetSocketWait
+{
+   ENET_SOCKET_WAIT_NONE      = 0,
+   ENET_SOCKET_WAIT_SEND      = (1 << 0),
+   ENET_SOCKET_WAIT_RECEIVE   = (1 << 1),
+   ENET_SOCKET_WAIT_INTERRUPT = (1 << 2)
+} ENetSocketWait;
+
+typedef enum _ENetSocketOption
+{
+   ENET_SOCKOPT_NONBLOCK  = 1,
+   ENET_SOCKOPT_BROADCAST = 2,
+   ENET_SOCKOPT_RCVBUF    = 3,
+   ENET_SOCKOPT_SNDBUF    = 4,
+   ENET_SOCKOPT_REUSEADDR = 5,
+   ENET_SOCKOPT_RCVTIMEO  = 6,
+   ENET_SOCKOPT_SNDTIMEO  = 7,
+   ENET_SOCKOPT_ERROR     = 8,
+   ENET_SOCKOPT_NODELAY   = 9
+} ENetSocketOption;
+
+typedef enum _ENetSocketShutdown
+{
+    ENET_SOCKET_SHUTDOWN_READ       = 0,
+    ENET_SOCKET_SHUTDOWN_WRITE      = 1,
+    ENET_SOCKET_SHUTDOWN_READ_WRITE = 2
+} ENetSocketShutdown;
+
+#define ENET_HOST_ANY       0
+#define ENET_HOST_BROADCAST 0xFFFFFFFFU
+#define ENET_PORT_ANY       0
+
+/**
+ * Portable internet address structure.
+ *
+ * The host must be specified in network byte-order, and the port must be in host
+ * byte-order. The constant ENET_HOST_ANY may be used to specify the default
+ * server host. The constant ENET_HOST_BROADCAST may be used to specify the
+ * broadcast address (255.255.255.255).  This makes sense for enet_host_connect,
+ * but not for enet_host_create.  Once a server responds to a broadcast, the
+ * address is updated from ENET_HOST_BROADCAST to the server's actual IP address.
+ */
+typedef struct _ENetAddress
+{
+   enet_uint32 host;
+   enet_uint16 port;
+} ENetAddress;
+
+/**
+ * Packet flag bit constants.
+ *
+ * The host must be specified in network byte-order, and the port must be in
+ * host byte-order. The constant ENET_HOST_ANY may be used to specify the
+ * default server host.
+
+   @sa ENetPacket
+*/
+typedef enum _ENetPacketFlag
+{
+   /** packet must be received by the target peer and resend attempts should be
+     * made until the packet is delivered */
+   ENET_PACKET_FLAG_RELIABLE    = (1 << 0),
+   /** packet will not be sequenced with other packets
+     * not supported for reliable packets
+     */
+   ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1),
+   /** packet will not allocate data, and user must supply it instead */
+   ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2),
+   /** packet will be fragmented using unreliable (instead of reliable) sends
+     * if it exceeds the MTU */
+   ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3),
+
+   /** whether the packet has been sent from all queues it has been entered into */
+   ENET_PACKET_FLAG_SENT = (1<<8)
+} ENetPacketFlag;
+
+typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *);
+
+/**
+ * ENet packet structure.
+ *
+ * An ENet data packet that may be sent to or received from a peer. The shown
+ * fields should only be read and never modified. The data field contains the
+ * allocated data for the packet. The dataLength fields specifies the length
+ * of the allocated data.  The flags field is either 0 (specifying no flags),
+ * or a bitwise-or of any combination of the following flags:
+ *
+ *    ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer
+ *    and resend attempts should be made until the packet is delivered
+ *
+ *    ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets
+ *    (not supported for reliable packets)
+ *
+ *    ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead
+ *
+ *    ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable
+ *    (instead of reliable) sends if it exceeds the MTU
+ *
+ *    ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into
+   @sa ENetPacketFlag
+ */
+typedef struct _ENetPacket
+{
+   size_t                   referenceCount;  /**< internal use only */
+   enet_uint32              flags;           /**< bitwise-or of ENetPacketFlag constants */
+   enet_uint8 *             data;            /**< allocated data for packet */
+   size_t                   dataLength;      /**< length of data */
+   ENetPacketFreeCallback   freeCallback;    /**< function to be called when the packet is no longer in use */
+   void *                   userData;        /**< application private data, may be freely modified */
+} ENetPacket;
+
+typedef struct _ENetAcknowledgement
+{
+   ENetListNode acknowledgementList;
+   enet_uint32  sentTime;
+   ENetProtocol command;
+} ENetAcknowledgement;
+
+typedef struct _ENetOutgoingCommand
+{
+   ENetListNode outgoingCommandList;
+   enet_uint16  reliableSequenceNumber;
+   enet_uint16  unreliableSequenceNumber;
+   enet_uint32  sentTime;
+   enet_uint32  roundTripTimeout;
+   enet_uint32  roundTripTimeoutLimit;
+   enet_uint32  fragmentOffset;
+   enet_uint16  fragmentLength;
+   enet_uint16  sendAttempts;
+   ENetProtocol command;
+   ENetPacket * packet;
+} ENetOutgoingCommand;
+
+typedef struct _ENetIncomingCommand
+{
+   ENetListNode     incomingCommandList;
+   enet_uint16      reliableSequenceNumber;
+   enet_uint16      unreliableSequenceNumber;
+   ENetProtocol     command;
+   enet_uint32      fragmentCount;
+   enet_uint32      fragmentsRemaining;
+   enet_uint32 *    fragments;
+   ENetPacket *     packet;
+} ENetIncomingCommand;
+
+typedef enum _ENetPeerState
+{
+   ENET_PEER_STATE_DISCONNECTED                = 0,
+   ENET_PEER_STATE_CONNECTING                  = 1,
+   ENET_PEER_STATE_ACKNOWLEDGING_CONNECT       = 2,
+   ENET_PEER_STATE_CONNECTION_PENDING          = 3,
+   ENET_PEER_STATE_CONNECTION_SUCCEEDED        = 4,
+   ENET_PEER_STATE_CONNECTED                   = 5,
+   ENET_PEER_STATE_DISCONNECT_LATER            = 6,
+   ENET_PEER_STATE_DISCONNECTING               = 7,
+   ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT    = 8,
+   ENET_PEER_STATE_ZOMBIE                      = 9
+} ENetPeerState;
+
+#ifndef ENET_BUFFER_MAXIMUM
+#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS)
+#endif
+
+enum
+{
+   ENET_HOST_RECEIVE_BUFFER_SIZE          = 256 * 1024,
+   ENET_HOST_SEND_BUFFER_SIZE             = 256 * 1024,
+   ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL  = 1000,
+   ENET_HOST_DEFAULT_MTU                  = 1400,
+   ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE  = 32 * 1024 * 1024,
+   ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024,
+
+   ENET_PEER_DEFAULT_ROUND_TRIP_TIME      = 500,
+   ENET_PEER_DEFAULT_PACKET_THROTTLE      = 32,
+   ENET_PEER_PACKET_THROTTLE_SCALE        = 32,
+   ENET_PEER_PACKET_THROTTLE_COUNTER      = 7,
+   ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2,
+   ENET_PEER_PACKET_THROTTLE_DECELERATION = 2,
+   ENET_PEER_PACKET_THROTTLE_INTERVAL     = 5000,
+   ENET_PEER_PACKET_LOSS_SCALE            = (1 << 16),
+   ENET_PEER_PACKET_LOSS_INTERVAL         = 10000,
+   ENET_PEER_WINDOW_SIZE_SCALE            = 64 * 1024,
+   ENET_PEER_TIMEOUT_LIMIT                = 32,
+   ENET_PEER_TIMEOUT_MINIMUM              = 5000,
+   ENET_PEER_TIMEOUT_MAXIMUM              = 30000,
+   ENET_PEER_PING_INTERVAL                = 500,
+   ENET_PEER_UNSEQUENCED_WINDOWS          = 64,
+   ENET_PEER_UNSEQUENCED_WINDOW_SIZE      = 1024,
+   ENET_PEER_FREE_UNSEQUENCED_WINDOWS     = 32,
+   ENET_PEER_RELIABLE_WINDOWS             = 16,
+   ENET_PEER_RELIABLE_WINDOW_SIZE         = 0x1000,
+   ENET_PEER_FREE_RELIABLE_WINDOWS        = 8
+};
+
+typedef struct _ENetChannel
+{
+   enet_uint16  outgoingReliableSequenceNumber;
+   enet_uint16  outgoingUnreliableSequenceNumber;
+   enet_uint16  usedReliableWindows;
+   enet_uint16  reliableWindows [ENET_PEER_RELIABLE_WINDOWS];
+   enet_uint16  incomingReliableSequenceNumber;
+   enet_uint16  incomingUnreliableSequenceNumber;
+   ENetList     incomingReliableCommands;
+   ENetList     incomingUnreliableCommands;
+} ENetChannel;
+
+/**
+ * An ENet peer which data packets may be sent or received from.
+ *
+ * No fields should be modified unless otherwise specified.
+ */
+typedef struct _ENetPeer
+{
+   ENetListNode  dispatchList;
+   struct _ENetHost * host;
+   enet_uint16   outgoingPeerID;
+   enet_uint16   incomingPeerID;
+   enet_uint32   connectID;
+   enet_uint8    outgoingSessionID;
+   enet_uint8    incomingSessionID;
+   ENetAddress   address;            /**< Internet address of the peer */
+   void *        data;               /**< Application private data, may be freely modified */
+   ENetPeerState state;
+   ENetChannel * channels;
+   size_t        channelCount;       /**< Number of channels allocated for communication with peer */
+   enet_uint32   incomingBandwidth;  /**< Downstream bandwidth of the client in bytes/second */
+   enet_uint32   outgoingBandwidth;  /**< Upstream bandwidth of the client in bytes/second */
+   enet_uint32   incomingBandwidthThrottleEpoch;
+   enet_uint32   outgoingBandwidthThrottleEpoch;
+   enet_uint32   incomingDataTotal;
+   enet_uint32   outgoingDataTotal;
+   enet_uint32   lastSendTime;
+   enet_uint32   lastReceiveTime;
+   enet_uint32   nextTimeout;
+   enet_uint32   earliestTimeout;
+   enet_uint32   packetLossEpoch;
+   enet_uint32   packetsSent;
+   enet_uint32   packetsLost;
+   enet_uint32   packetLoss;          /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */
+   enet_uint32   packetLossVariance;
+   enet_uint32   packetThrottle;
+   enet_uint32   packetThrottleLimit;
+   enet_uint32   packetThrottleCounter;
+   enet_uint32   packetThrottleEpoch;
+   enet_uint32   packetThrottleAcceleration;
+   enet_uint32   packetThrottleDeceleration;
+   enet_uint32   packetThrottleInterval;
+   enet_uint32   pingInterval;
+   enet_uint32   timeoutLimit;
+   enet_uint32   timeoutMinimum;
+   enet_uint32   timeoutMaximum;
+   enet_uint32   lastRoundTripTime;
+   enet_uint32   lowestRoundTripTime;
+   enet_uint32   lastRoundTripTimeVariance;
+   enet_uint32   highestRoundTripTimeVariance;
+   enet_uint32   roundTripTime;            /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */
+   enet_uint32   roundTripTimeVariance;
+   enet_uint32   mtu;
+   enet_uint32   windowSize;
+   enet_uint32   reliableDataInTransit;
+   enet_uint16   outgoingReliableSequenceNumber;
+   ENetList      acknowledgements;
+   ENetList      sentReliableCommands;
+   ENetList      sentUnreliableCommands;
+   ENetList      outgoingReliableCommands;
+   ENetList      outgoingUnreliableCommands;
+   ENetList      dispatchedCommands;
+   int           needsDispatch;
+   enet_uint16   incomingUnsequencedGroup;
+   enet_uint16   outgoingUnsequencedGroup;
+   enet_uint32   unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32];
+   enet_uint32   eventData;
+   size_t        totalWaitingData;
+} ENetPeer;
+
+/** An ENet packet compressor for compressing UDP packets before socket sends or receives.
+ */
+typedef struct _ENetCompressor
+{
+   /** Context data for the compressor. Must be non-NULL. */
+   void * context;
+   /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
+   size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit);
+   /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
+   size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit);
+   /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */
+   void (ENET_CALLBACK * destroy) (void * context);
+} ENetCompressor;
+
+/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */
+typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount);
+
+/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */
+typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event);
+
+/** An ENet host for communicating with peers.
+  *
+  * No fields should be modified unless otherwise stated.
+
+    @sa enet_host_create()
+    @sa enet_host_destroy()
+    @sa enet_host_connect()
+    @sa enet_host_service()
+    @sa enet_host_flush()
+    @sa enet_host_broadcast()
+    @sa enet_host_compress()
+    @sa enet_host_compress_with_range_coder()
+    @sa enet_host_channel_limit()
+    @sa enet_host_bandwidth_limit()
+    @sa enet_host_bandwidth_throttle()
+  */
+typedef struct _ENetHost
+{
+   ENetSocket           socket;
+   ENetAddress          address;                     /**< Internet address of the host */
+   enet_uint32          incomingBandwidth;           /**< downstream bandwidth of the host */
+   enet_uint32          outgoingBandwidth;           /**< upstream bandwidth of the host */
+   enet_uint32          bandwidthThrottleEpoch;
+   enet_uint32          mtu;
+   enet_uint32          randomSeed;
+   int                  recalculateBandwidthLimits;
+   ENetPeer *           peers;                       /**< array of peers allocated for this host */
+   size_t               peerCount;                   /**< number of peers allocated for this host */
+   size_t               channelLimit;                /**< maximum number of channels allowed for connected peers */
+   enet_uint32          serviceTime;
+   ENetList             dispatchQueue;
+   int                  continueSending;
+   size_t               packetSize;
+   enet_uint16          headerFlags;
+   ENetProtocol         commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS];
+   size_t               commandCount;
+   ENetBuffer           buffers [ENET_BUFFER_MAXIMUM];
+   size_t               bufferCount;
+   ENetChecksumCallback checksum;                    /**< callback the user can set to enable packet checksums for this host */
+   ENetCompressor       compressor;
+   enet_uint8           packetData [2][ENET_PROTOCOL_MAXIMUM_MTU];
+   ENetAddress          receivedAddress;
+   enet_uint8 *         receivedData;
+   size_t               receivedDataLength;
+   enet_uint32          totalSentData;               /**< total data sent, user should reset to 0 as needed to prevent overflow */
+   enet_uint32          totalSentPackets;            /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */
+   enet_uint32          totalReceivedData;           /**< total data received, user should reset to 0 as needed to prevent overflow */
+   enet_uint32          totalReceivedPackets;        /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */
+   ENetInterceptCallback intercept;                  /**< callback the user can set to intercept received raw UDP packets */
+   size_t               connectedPeers;
+   size_t               bandwidthLimitedPeers;
+   size_t               duplicatePeers;              /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */
+   size_t               maximumPacketSize;           /**< the maximum allowable packet size that may be sent or received on a peer */
+   size_t               maximumWaitingData;          /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */
+} ENetHost;
+
+/**
+ * An ENet event type, as specified in @ref ENetEvent.
+ */
+typedef enum _ENetEventType
+{
+   /** no event occurred within the specified time limit */
+   ENET_EVENT_TYPE_NONE       = 0,
+
+   /** a connection request initiated by enet_host_connect has completed.
+     * The peer field contains the peer which successfully connected.
+     */
+   ENET_EVENT_TYPE_CONNECT    = 1,
+
+   /** a peer has disconnected.  This event is generated on a successful
+     * completion of a disconnect initiated by enet_peer_disconnect, if
+     * a peer has timed out, or if a connection request intialized by
+     * enet_host_connect has timed out.  The peer field contains the peer
+     * which disconnected. The data field contains user supplied data
+     * describing the disconnection, or 0, if none is available.
+     */
+   ENET_EVENT_TYPE_DISCONNECT = 2,
+
+   /** a packet has been received from a peer.  The peer field specifies the
+     * peer which sent the packet.  The channelID field specifies the channel
+     * number upon which the packet was received.  The packet field contains
+     * the packet that was received; this packet must be destroyed with
+     * enet_packet_destroy after use.
+     */
+   ENET_EVENT_TYPE_RECEIVE    = 3
+} ENetEventType;
+
+/**
+ * An ENet event as returned by enet_host_service().
+
+   @sa enet_host_service
+ */
+typedef struct _ENetEvent
+{
+   ENetEventType        type;      /**< type of the event */
+   ENetPeer *           peer;      /**< peer that generated a connect, disconnect or receive event */
+   enet_uint8           channelID; /**< channel on the peer that generated the event, if appropriate */
+   enet_uint32          data;      /**< data associated with the event, if appropriate */
+   ENetPacket *         packet;    /**< packet associated with the event, if appropriate */
+} ENetEvent;
+
+/** @defgroup global ENet global functions
+    @{
+*/
+
+/**
+  Initializes ENet globally.  Must be called prior to using any functions in
+  ENet.
+  @returns 0 on success, < 0 on failure
+*/
+ENET_API int enet_initialize (void);
+
+/**
+  Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored.
+
+  @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use
+  @param inits user-overridden callbacks where any NULL callbacks will use ENet's defaults
+  @returns 0 on success, < 0 on failure
+*/
+ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits);
+
+/**
+  Shuts down ENet globally.  Should be called when a program that has
+  initialized ENet exits.
+*/
+ENET_API void enet_deinitialize (void);
+
+/**
+  Gives the linked version of the ENet library.
+  @returns the version number
+*/
+ENET_API ENetVersion enet_linked_version (void);
+
+/** @} */
+
+/** @defgroup private ENet private implementation functions */
+
+/**
+  Returns the wall-time in milliseconds.  Its initial value is unspecified
+  unless otherwise set.
+  */
+ENET_API enet_uint64 enet_time_get (void);
+/**
+  Sets the current wall-time in milliseconds.
+  */
+ENET_API void enet_time_set (enet_uint64);
+
+/** @defgroup socket ENet socket functions
+    @{
+*/
+ENET_API ENetSocket enet_socket_create (ENetSocketType);
+ENET_API int        enet_socket_bind (ENetSocket, const ENetAddress *);
+ENET_API int        enet_socket_get_address (ENetSocket, ENetAddress *);
+ENET_API int        enet_socket_listen (ENetSocket, int);
+ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *);
+ENET_API int        enet_socket_connect (ENetSocket, const ENetAddress *);
+ENET_API int        enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t);
+ENET_API int        enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t);
+ENET_API int        enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint64);
+ENET_API int        enet_socket_set_option (ENetSocket, ENetSocketOption, int);
+ENET_API int        enet_socket_get_option (ENetSocket, ENetSocketOption, int *);
+ENET_API int        enet_socket_shutdown (ENetSocket, ENetSocketShutdown);
+ENET_API void       enet_socket_destroy (ENetSocket);
+ENET_API int        enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32);
+
+/** @} */
+
+/** @defgroup Address ENet address functions
+    @{
+*/
+
+/** Attempts to parse the printable form of the IP address in the parameter hostName
+    and sets the host field in the address parameter if successful.
+    @param address destination to store the parsed IP address
+    @param hostName IP address to parse
+    @retval 0 on success
+    @retval < 0 on failure
+    @returns the address of the given hostName in address on success
+*/
+ENET_API int enet_address_set_host_ip (ENetAddress * address, const char * hostName);
+
+/** Attempts to resolve the host named by the parameter hostName and sets
+    the host field in the address parameter if successful.
+    @param address destination to store resolved address
+    @param hostName host name to lookup
+    @retval 0 on success
+    @retval < 0 on failure
+    @returns the address of the given hostName in address on success
+*/
+ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName);
+
+/** Gives the printable form of the IP address specified in the address parameter.
+    @param address    address printed
+    @param hostName   destination for name, must not be NULL
+    @param nameLength maximum length of hostName.
+    @returns the null-terminated name of the host in hostName on success
+    @retval 0 on success
+    @retval < 0 on failure
+*/
+ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength);
+
+/** Attempts to do a reverse lookup of the host field in the address parameter.
+    @param address    address used for reverse lookup
+    @param hostName   destination for name, must not be NULL
+    @param nameLength maximum length of hostName.
+    @returns the null-terminated name of the host in hostName on success
+    @retval 0 on success
+    @retval < 0 on failure
+*/
+ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength);
+
+/** @} */
+
+ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32);
+ENET_API void         enet_packet_destroy (ENetPacket *);
+ENET_API int          enet_packet_resize  (ENetPacket *, size_t);
+ENET_API enet_uint32  enet_crc32 (const ENetBuffer *, size_t);
+
+ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32);
+ENET_API void       enet_host_destroy (ENetHost *);
+ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32);
+ENET_API int        enet_host_check_events (ENetHost *, ENetEvent *);
+ENET_API int        enet_host_service (ENetHost *, ENetEvent *, enet_uint32);
+ENET_API void       enet_host_flush (ENetHost *);
+ENET_API void       enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *);
+ENET_API void       enet_host_compress (ENetHost *, const ENetCompressor *);
+ENET_API int        enet_host_compress_with_range_coder (ENetHost * host);
+ENET_API void       enet_host_channel_limit (ENetHost *, size_t);
+ENET_API void       enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32);
+extern   void       enet_host_bandwidth_throttle (ENetHost *);
+extern  enet_uint64 enet_host_random_seed (void);
+
+ENET_API int                 enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *);
+ENET_API ENetPacket *        enet_peer_receive (ENetPeer *, enet_uint8 * channelID);
+ENET_API void                enet_peer_ping (ENetPeer *);
+ENET_API void                enet_peer_ping_interval (ENetPeer *, enet_uint32);
+ENET_API void                enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
+ENET_API void                enet_peer_reset (ENetPeer *);
+ENET_API void                enet_peer_disconnect (ENetPeer *, enet_uint32);
+ENET_API void                enet_peer_disconnect_now (ENetPeer *, enet_uint32);
+ENET_API void                enet_peer_disconnect_later (ENetPeer *, enet_uint32);
+ENET_API void                enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
+extern int                   enet_peer_throttle (ENetPeer *, enet_uint32);
+extern void                  enet_peer_reset_queues (ENetPeer *);
+extern void                  enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *);
+extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16);
+extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32);
+extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16);
+extern void                  enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *);
+extern void                  enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *);
+extern void                  enet_peer_on_connect (ENetPeer *);
+extern void                  enet_peer_on_disconnect (ENetPeer *);
+
+ENET_API void * enet_range_coder_create (void);
+ENET_API void   enet_range_coder_destroy (void *);
+ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t);
+ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t);
+
+extern size_t enet_protocol_command_size (enet_uint8);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#if defined(ENET_IMPLEMENTATION) && !defined(ENET_IMPLEMENTATION_DONE)
+#define ENET_IMPLEMENTATION_DONE
+
+    #define ENET_BUILDING_LIB 1
+
+    #ifdef __cplusplus
+    extern "C"
+    {
+    #endif
+
+    // @from_file: callbacks.c
+    /**
+     @file callbacks.c
+     @brief ENet callback functions
+    */
+    #define ENET_BUILDING_LIB 1
+
+
+    static ENetCallbacks callbacks = { malloc, free, abort };
+
+    int
+    enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits)
+    {
+       if (version < ENET_VERSION_CREATE (1, 3, 0))
+         return -1;
+
+       if (inits -> malloc != NULL || inits -> free != NULL)
+       {
+          if (inits -> malloc == NULL || inits -> free == NULL)
+            return -1;
+
+          callbacks.malloc = inits -> malloc;
+          callbacks.free = inits -> free;
+       }
+
+       if (inits -> no_memory != NULL)
+         callbacks.no_memory = inits -> no_memory;
+
+       return enet_initialize ();
+    }
+
+    ENetVersion
+    enet_linked_version (void)
+    {
+        return ENET_VERSION;
+    }
+
+    void *
+    enet_malloc (size_t size)
+    {
+       void * memory = callbacks.malloc (size);
+
+       if (memory == NULL)
+         callbacks.no_memory ();
+
+       return memory;
+    }
+
+    void
+    enet_free (void * memory)
+    {
+       callbacks.free (memory);
+    }
+
+    // @from_file: compress.c
+    /**
+     @file compress.c
+     @brief An adaptive order-2 PPM range coder
+    */
+    #define ENET_BUILDING_LIB 1
+    #include <string.h>
+
+
+    typedef struct _ENetSymbol
+    {
+        /* binary indexed tree of symbols */
+        enet_uint8 value;
+        enet_uint8 count;
+        enet_uint16 under;
+        enet_uint16 left, right;
+
+        /* context defined by this symbol */
+        enet_uint16 symbols;
+        enet_uint16 escapes;
+        enet_uint16 total;
+        enet_uint16 parent;
+    } ENetSymbol;
+
+    /* adaptation constants tuned aggressively for small packet sizes rather than large file compression */
+    enum
+    {
+        ENET_RANGE_CODER_TOP    = 1<<24,
+        ENET_RANGE_CODER_BOTTOM = 1<<16,
+
+        ENET_CONTEXT_SYMBOL_DELTA = 3,
+        ENET_CONTEXT_SYMBOL_MINIMUM = 1,
+        ENET_CONTEXT_ESCAPE_MINIMUM = 1,
+
+        ENET_SUBCONTEXT_ORDER = 2,
+        ENET_SUBCONTEXT_SYMBOL_DELTA = 2,
+        ENET_SUBCONTEXT_ESCAPE_DELTA = 5
+    };
+
+    /* context exclusion roughly halves compression speed, so disable for now */
+    #undef ENET_CONTEXT_EXCLUSION
+
+    typedef struct _ENetRangeCoder
+    {
+        /* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */
+        ENetSymbol symbols[4096];
+    } ENetRangeCoder;
+
+    void *
+    enet_range_coder_create (void)
+    {
+        ENetRangeCoder * rangeCoder = (ENetRangeCoder *) enet_malloc (sizeof (ENetRangeCoder));
+        if (rangeCoder == NULL)
+          return NULL;
+
+        return rangeCoder;
+    }
+
+    void
+    enet_range_coder_destroy (void * context)
+    {
+        ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
+        if (rangeCoder == NULL)
+          return;
+
+        enet_free (rangeCoder);
+    }
+
+    #define ENET_SYMBOL_CREATE(symbol, value_, count_) \
+    { \
+        symbol = & rangeCoder -> symbols [nextSymbol ++]; \
+        symbol -> value = value_; \
+        symbol -> count = count_; \
+        symbol -> under = count_; \
+        symbol -> left = 0; \
+        symbol -> right = 0; \
+        symbol -> symbols = 0; \
+        symbol -> escapes = 0; \
+        symbol -> total = 0; \
+        symbol -> parent = 0; \
+    }
+
+    #define ENET_CONTEXT_CREATE(context, escapes_, minimum) \
+    { \
+        ENET_SYMBOL_CREATE (context, 0, 0); \
+        (context) -> escapes = escapes_; \
+        (context) -> total = escapes_ + 256*minimum; \
+        (context) -> symbols = 0; \
+    }
+
+    static enet_uint16
+    enet_symbol_rescale (ENetSymbol * symbol)
+    {
+        enet_uint16 total = 0;
+        for (;;)
+        {
+            symbol -> count -= symbol->count >> 1;
+            symbol -> under = symbol -> count;
+            if (symbol -> left)
+              symbol -> under += enet_symbol_rescale (symbol + symbol -> left);
+            total += symbol -> under;
+            if (! symbol -> right) break;
+            symbol += symbol -> right;
+        }
+        return total;
+    }
+
+    #define ENET_CONTEXT_RESCALE(context, minimum) \
+    { \
+        (context) -> total = (context) -> symbols ? enet_symbol_rescale ((context) + (context) -> symbols) : 0; \
+        (context) -> escapes -= (context) -> escapes >> 1; \
+        (context) -> total += (context) -> escapes + 256*minimum; \
+    }
+
+    #define ENET_RANGE_CODER_OUTPUT(value) \
+    { \
+        if (outData >= outEnd) \
+          return 0; \
+        * outData ++ = value; \
+    }
+
+    #define ENET_RANGE_CODER_ENCODE(under, count, total) \
+    { \
+        encodeRange /= (total); \
+        encodeLow += (under) * encodeRange; \
+        encodeRange *= (count); \
+        for (;;) \
+        { \
+            if((encodeLow ^ (encodeLow + encodeRange)) >= ENET_RANGE_CODER_TOP) \
+            { \
+                if(encodeRange >= ENET_RANGE_CODER_BOTTOM) break; \
+                encodeRange = -encodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \
+            } \
+            ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \
+            encodeRange <<= 8; \
+            encodeLow <<= 8; \
+        } \
+    }
+
+    #define ENET_RANGE_CODER_FLUSH \
+    { \
+        while (encodeLow) \
+        { \
+            ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \
+            encodeLow <<= 8; \
+        } \
+    }
+
+    #define ENET_RANGE_CODER_FREE_SYMBOLS \
+    { \
+        if (nextSymbol >= sizeof (rangeCoder -> symbols) / sizeof (ENetSymbol) - ENET_SUBCONTEXT_ORDER ) \
+        { \
+            nextSymbol = 0; \
+            ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); \
+            predicted = 0; \
+            order = 0; \
+        } \
+    }
+
+    #define ENET_CONTEXT_ENCODE(context, symbol_, value_, under_, count_, update, minimum) \
+    { \
+        under_ = value*minimum; \
+        count_ = minimum; \
+        if (! (context) -> symbols) \
+        { \
+            ENET_SYMBOL_CREATE (symbol_, value_, update); \
+            (context) -> symbols = symbol_ - (context); \
+        } \
+        else \
+        { \
+            ENetSymbol * node = (context) + (context) -> symbols; \
+            for (;;) \
+            { \
+                if (value_ < node -> value) \
+                { \
+                    node -> under += update; \
+                    if (node -> left) { node += node -> left; continue; } \
+                    ENET_SYMBOL_CREATE (symbol_, value_, update); \
+                    node -> left = symbol_ - node; \
+                } \
+                else \
+                if (value_ > node -> value) \
+                { \
+                    under_ += node -> under; \
+                    if (node -> right) { node += node -> right; continue; } \
+                    ENET_SYMBOL_CREATE (symbol_, value_, update); \
+                    node -> right = symbol_ - node; \
+                } \
+                else \
+                { \
+                    count_ += node -> count; \
+                    under_ += node -> under - node -> count; \
+                    node -> under += update; \
+                    node -> count += update; \
+                    symbol_ = node; \
+                } \
+                break; \
+            } \
+        } \
+    }
+
+    #ifdef ENET_CONTEXT_EXCLUSION
+    static const ENetSymbol emptyContext = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+    #define ENET_CONTEXT_WALK(context, body) \
+    { \
+        const ENetSymbol * node = (context) + (context) -> symbols; \
+        const ENetSymbol * stack [256]; \
+        size_t stackSize = 0; \
+        while (node -> left) \
+        { \
+            stack [stackSize ++] = node; \
+            node += node -> left; \
+        } \
+        for (;;) \
+        { \
+            body; \
+            if (node -> right) \
+            { \
+                node += node -> right; \
+                while (node -> left) \
+                { \
+                    stack [stackSize ++] = node; \
+                    node += node -> left; \
+                } \
+            } \
+            else \
+            if (stackSize <= 0) \
+                break; \
+            else \
+                node = stack [-- stackSize]; \
+        } \
+    }
+
+    #define ENET_CONTEXT_ENCODE_EXCLUDE(context, value_, under, total, minimum) \
+    ENET_CONTEXT_WALK(context, { \
+        if (node -> value != value_) \
+        { \
+            enet_uint16 parentCount = rangeCoder -> symbols [node -> parent].count + minimum; \
+            if (node -> value < value_) \
+              under -= parentCount; \
+            total -= parentCount; \
+        } \
+    })
+    #endif
+
+    size_t
+    enet_range_coder_compress (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit)
+    {
+        ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
+        enet_uint8 * outStart = outData, * outEnd = & outData [outLimit];
+        const enet_uint8 * inData, * inEnd;
+        enet_uint32 encodeLow = 0, encodeRange = ~0;
+        ENetSymbol * root;
+        enet_uint16 predicted = 0;
+        size_t order = 0, nextSymbol = 0;
+
+        if (rangeCoder == NULL || inBufferCount <= 0 || inLimit <= 0)
+          return 0;
+
+        inData = (const enet_uint8 *) inBuffers -> data;
+        inEnd = & inData [inBuffers -> dataLength];
+        inBuffers ++;
+        inBufferCount --;
+
+        ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM);
+
+        for (;;)
+        {
+            ENetSymbol * subcontext, * symbol;
+    #ifdef ENET_CONTEXT_EXCLUSION
+            const ENetSymbol * childContext = & emptyContext;
+    #endif
+            enet_uint8 value;
+            enet_uint16 count, under, * parent = & predicted, total;
+            if (inData >= inEnd)
+            {
+                if (inBufferCount <= 0)
+                  break;
+                inData = (const enet_uint8 *) inBuffers -> data;
+                inEnd = & inData [inBuffers -> dataLength];
+                inBuffers ++;
+                inBufferCount --;
+            }
+            value = * inData ++;
+
+            for (subcontext = & rangeCoder -> symbols [predicted];
+                 subcontext != root;
+    #ifdef ENET_CONTEXT_EXCLUSION
+                 childContext = subcontext,
+    #endif
+                    subcontext = & rangeCoder -> symbols [subcontext -> parent])
+            {
+                ENET_CONTEXT_ENCODE (subcontext, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0);
+                * parent = symbol - rangeCoder -> symbols;
+                parent = & symbol -> parent;
+                total = subcontext -> total;
+    #ifdef ENET_CONTEXT_EXCLUSION
+                if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA)
+                  ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, 0);
+    #endif
+                if (count > 0)
+                {
+                    ENET_RANGE_CODER_ENCODE (subcontext -> escapes + under, count, total);
+                }
+                else
+                {
+                    if (subcontext -> escapes > 0 && subcontext -> escapes < total)
+                        ENET_RANGE_CODER_ENCODE (0, subcontext -> escapes, total);
+                    subcontext -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA;
+                    subcontext -> total += ENET_SUBCONTEXT_ESCAPE_DELTA;
+                }
+                subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
+                if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
+                  ENET_CONTEXT_RESCALE (subcontext, 0);
+                if (count > 0) goto nextInput;
+            }
+
+            ENET_CONTEXT_ENCODE (root, symbol, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM);
+            * parent = symbol - rangeCoder -> symbols;
+            parent = & symbol -> parent;
+            total = root -> total;
+    #ifdef ENET_CONTEXT_EXCLUSION
+            if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA)
+              ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, ENET_CONTEXT_SYMBOL_MINIMUM);
+    #endif
+            ENET_RANGE_CODER_ENCODE (root -> escapes + under, count, total);
+            root -> total += ENET_CONTEXT_SYMBOL_DELTA;
+            if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
+              ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM);
+
+        nextInput:
+            if (order >= ENET_SUBCONTEXT_ORDER)
+              predicted = rangeCoder -> symbols [predicted].parent;
+            else
+              order ++;
+            ENET_RANGE_CODER_FREE_SYMBOLS;
+        }
+
+        ENET_RANGE_CODER_FLUSH;
+
+        return (size_t) (outData - outStart);
+    }
+
+    #define ENET_RANGE_CODER_SEED \
+    { \
+        if (inData < inEnd) decodeCode |= * inData ++ << 24; \
+        if (inData < inEnd) decodeCode |= * inData ++ << 16; \
+        if (inData < inEnd) decodeCode |= * inData ++ << 8; \
+        if (inData < inEnd) decodeCode |= * inData ++; \
+    }
+
+    #define ENET_RANGE_CODER_READ(total) ((decodeCode - decodeLow) / (decodeRange /= (total)))
+
+    #define ENET_RANGE_CODER_DECODE(under, count, total) \
+    { \
+        decodeLow += (under) * decodeRange; \
+        decodeRange *= (count); \
+        for (;;) \
+        { \
+            if((decodeLow ^ (decodeLow + decodeRange)) >= ENET_RANGE_CODER_TOP) \
+            { \
+                if(decodeRange >= ENET_RANGE_CODER_BOTTOM) break; \
+                decodeRange = -decodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \
+            } \
+            decodeCode <<= 8; \
+            if (inData < inEnd) \
+              decodeCode |= * inData ++; \
+            decodeRange <<= 8; \
+            decodeLow <<= 8; \
+        } \
+    }
+
+    #define ENET_CONTEXT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, createRoot, visitNode, createRight, createLeft) \
+    { \
+        under_ = 0; \
+        count_ = minimum; \
+        if (! (context) -> symbols) \
+        { \
+            createRoot; \
+        } \
+        else \
+        { \
+            ENetSymbol * node = (context) + (context) -> symbols; \
+            for (;;) \
+            { \
+                enet_uint16 after = under_ + node -> under + (node -> value + 1)*minimum, before = node -> count + minimum; \
+                visitNode; \
+                if (code >= after) \
+                { \
+                    under_ += node -> under; \
+                    if (node -> right) { node += node -> right; continue; } \
+                    createRight; \
+                } \
+                else \
+                if (code < after - before) \
+                { \
+                    node -> under += update; \
+                    if (node -> left) { node += node -> left; continue; } \
+                    createLeft; \
+                } \
+                else \
+                { \
+                    value_ = node -> value; \
+                    count_ += node -> count; \
+                    under_ = after - before; \
+                    node -> under += update; \
+                    node -> count += update; \
+                    symbol_ = node; \
+                } \
+                break; \
+            } \
+        } \
+    }
+
+    #define ENET_CONTEXT_TRY_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \
+    ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, return 0, exclude (node -> value, after, before), return 0, return 0)
+
+    #define ENET_CONTEXT_ROOT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \
+    ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, \
+        { \
+            value_ = code / minimum; \
+            under_ = code - code%minimum; \
+            ENET_SYMBOL_CREATE (symbol_, value_, update); \
+            (context) -> symbols = symbol_ - (context); \
+        }, \
+        exclude (node -> value, after, before), \
+        { \
+            value_ = node->value + 1 + (code - after)/minimum; \
+            under_ = code - (code - after)%minimum; \
+            ENET_SYMBOL_CREATE (symbol_, value_, update); \
+            node -> right = symbol_ - node; \
+        }, \
+        { \
+            value_ = node->value - 1 - (after - before - code - 1)/minimum; \
+            under_ = code - (after - before - code - 1)%minimum; \
+            ENET_SYMBOL_CREATE (symbol_, value_, update); \
+            node -> left = symbol_ - node; \
+        }) \
+
+    #ifdef ENET_CONTEXT_EXCLUSION
+    typedef struct _ENetExclude
+    {
+        enet_uint8 value;
+        enet_uint16 under;
+    } ENetExclude;
+
+    #define ENET_CONTEXT_DECODE_EXCLUDE(context, total, minimum) \
+    { \
+        enet_uint16 under = 0; \
+        nextExclude = excludes; \
+        ENET_CONTEXT_WALK (context, { \
+            under += rangeCoder -> symbols [node -> parent].count + minimum; \
+            nextExclude -> value = node -> value; \
+            nextExclude -> under = under; \
+            nextExclude ++; \
+        }); \
+        total -= under; \
+    }
+
+    #define ENET_CONTEXT_EXCLUDED(value_, after, before) \
+    { \
+        size_t low = 0, high = nextExclude - excludes; \
+        for(;;) \
+        { \
+            size_t mid = (low + high) >> 1; \
+            const ENetExclude * exclude = & excludes [mid]; \
+            if (value_ < exclude -> value) \
+            { \
+                if (low + 1 < high) \
+                { \
+                    high = mid; \
+                    continue; \
+                } \
+                if (exclude > excludes) \
+                  after -= exclude [-1].under; \
+            } \
+            else \
+            { \
+                if (value_ > exclude -> value) \
+                { \
+                    if (low + 1 < high) \
+                    { \
+                        low = mid; \
+                        continue; \
+                    } \
+                } \
+                else \
+                  before = 0; \
+                after -= exclude -> under; \
+            } \
+            break; \
+        } \
+    }
+    #endif
+
+    #define ENET_CONTEXT_NOT_EXCLUDED(value_, after, before)
+
+    size_t
+    enet_range_coder_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit)
+    {
+        ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
+        enet_uint8 * outStart = outData, * outEnd = & outData [outLimit];
+        const enet_uint8 * inEnd = & inData [inLimit];
+        enet_uint32 decodeLow = 0, decodeCode = 0, decodeRange = ~0;
+        ENetSymbol * root;
+        enet_uint16 predicted = 0;
+        size_t order = 0, nextSymbol = 0;
+    #ifdef ENET_CONTEXT_EXCLUSION
+        ENetExclude excludes [256];
+        ENetExclude * nextExclude = excludes;
+    #endif
+
+        if (rangeCoder == NULL || inLimit <= 0)
+          return 0;
+
+        ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM);
+
+        ENET_RANGE_CODER_SEED;
+
+        for (;;)
+        {
+            ENetSymbol * subcontext, * symbol, * patch;
+    #ifdef ENET_CONTEXT_EXCLUSION
+            const ENetSymbol * childContext = & emptyContext;
+    #endif
+            enet_uint8 value = 0;
+            enet_uint16 code, under, count, bottom, * parent = & predicted, total;
+
+            for (subcontext = & rangeCoder -> symbols [predicted];
+                 subcontext != root;
+    #ifdef ENET_CONTEXT_EXCLUSION
+                 childContext = subcontext,
+    #endif
+                    subcontext = & rangeCoder -> symbols [subcontext -> parent])
+            {
+                if (subcontext -> escapes <= 0)
+                  continue;
+                total = subcontext -> total;
+    #ifdef ENET_CONTEXT_EXCLUSION
+                if (childContext -> total > 0)
+                  ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, 0);
+    #endif
+                if (subcontext -> escapes >= total)
+                  continue;
+                code = ENET_RANGE_CODER_READ (total);
+                if (code < subcontext -> escapes)
+                {
+                    ENET_RANGE_CODER_DECODE (0, subcontext -> escapes, total);
+                    continue;
+                }
+                code -= subcontext -> escapes;
+    #ifdef ENET_CONTEXT_EXCLUSION
+                if (childContext -> total > 0)
+                {
+                    ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_EXCLUDED);
+                }
+                else
+    #endif
+                {
+                    ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_NOT_EXCLUDED);
+                }
+                bottom = symbol - rangeCoder -> symbols;
+                ENET_RANGE_CODER_DECODE (subcontext -> escapes + under, count, total);
+                subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
+                if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
+                  ENET_CONTEXT_RESCALE (subcontext, 0);
+                goto patchContexts;
+            }
+
+            total = root -> total;
+    #ifdef ENET_CONTEXT_EXCLUSION
+            if (childContext -> total > 0)
+              ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, ENET_CONTEXT_SYMBOL_MINIMUM);
+    #endif
+            code = ENET_RANGE_CODER_READ (total);
+            if (code < root -> escapes)
+            {
+                ENET_RANGE_CODER_DECODE (0, root -> escapes, total);
+                break;
+            }
+            code -= root -> escapes;
+    #ifdef ENET_CONTEXT_EXCLUSION
+            if (childContext -> total > 0)
+            {
+                ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_EXCLUDED);
+            }
+            else
+    #endif
+            {
+                ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_NOT_EXCLUDED);
+            }
+            bottom = symbol - rangeCoder -> symbols;
+            ENET_RANGE_CODER_DECODE (root -> escapes + under, count, total);
+            root -> total += ENET_CONTEXT_SYMBOL_DELTA;
+            if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
+              ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM);
+
+        patchContexts:
+            for (patch = & rangeCoder -> symbols [predicted];
+                 patch != subcontext;
+                 patch = & rangeCoder -> symbols [patch -> parent])
+            {
+                ENET_CONTEXT_ENCODE (patch, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0);
+                * parent = symbol - rangeCoder -> symbols;
+                parent = & symbol -> parent;
+                if (count <= 0)
+                {
+                    patch -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA;
+                    patch -> total += ENET_SUBCONTEXT_ESCAPE_DELTA;
+                }
+                patch -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
+                if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
+                  ENET_CONTEXT_RESCALE (patch, 0);
+            }
+            * parent = bottom;
+
+            ENET_RANGE_CODER_OUTPUT (value);
+
+            if (order >= ENET_SUBCONTEXT_ORDER)
+              predicted = rangeCoder -> symbols [predicted].parent;
+            else
+              order ++;
+            ENET_RANGE_CODER_FREE_SYMBOLS;
+        }
+
+        return (size_t) (outData - outStart);
+    }
+
+    /** @defgroup host ENet host functions
+        @{
+    */
+
+    /** Sets the packet compressor the host should use to the default range coder.
+        @param host host to enable the range coder for
+        @returns 0 on success, < 0 on failure
+    */
+    int
+    enet_host_compress_with_range_coder (ENetHost * host)
+    {
+        ENetCompressor compressor;
+        memset (& compressor, 0, sizeof (compressor));
+        compressor.context = enet_range_coder_create();
+        if (compressor.context == NULL)
+          return -1;
+        compressor.compress = enet_range_coder_compress;
+        compressor.decompress = enet_range_coder_decompress;
+        compressor.destroy = enet_range_coder_destroy;
+        enet_host_compress (host, & compressor);
+        return 0;
+    }
+
+    /** @} */
+
+    // @from_file: host.c
+    /**
+     @file host.c
+     @brief ENet host management functions
+    */
+    #define ENET_BUILDING_LIB 1
+
+
+
+    /** @defgroup host ENet host functions
+        @{
+    */
+
+    /** Creates a host for communicating to peers.
+
+        @param address   the address at which other peers may connect to this host.  If NULL, then no peers may connect to the host.
+        @param peerCount the maximum number of peers that should be allocated for the host.
+        @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
+        @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
+        @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
+
+        @returns the host on success and NULL on failure
+
+        @remarks ENet will strategically drop packets on specific sides of a connection between hosts
+        to ensure the host's bandwidth is not overwhelmed.  The bandwidth parameters also determine
+        the window size of a connection which limits the amount of reliable packets that may be in transit
+        at any given time.
+    */
+    ENetHost *
+    enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
+    {
+        ENetHost * host;
+        ENetPeer * currentPeer;
+
+        if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID)
+          return NULL;
+
+        host = (ENetHost *) enet_malloc (sizeof (ENetHost));
+        if (host == NULL)
+          return NULL;
+        memset (host, 0, sizeof (ENetHost));
+
+        host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer));
+        if (host -> peers == NULL)
+        {
+           enet_free (host);
+
+           return NULL;
+        }
+        memset (host -> peers, 0, peerCount * sizeof (ENetPeer));
+
+        host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM);
+        if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0))
+        {
+           if (host -> socket != ENET_SOCKET_NULL)
+             enet_socket_destroy (host -> socket);
+
+           enet_free (host -> peers);
+           enet_free (host);
+
+           return NULL;
+        }
+
+        enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1);
+        enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1);
+        enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE);
+        enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE);
+
+        if (address != NULL && enet_socket_get_address (host -> socket, & host -> address) < 0)
+          host -> address = * address;
+
+        if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
+          channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
+        else
+        if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
+          channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
+
+        host -> randomSeed = (enet_uint32) (size_t) host;
+        host -> randomSeed += enet_host_random_seed ();
+        host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 16);
+        host -> channelLimit = channelLimit;
+        host -> incomingBandwidth = incomingBandwidth;
+        host -> outgoingBandwidth = outgoingBandwidth;
+        host -> bandwidthThrottleEpoch = 0;
+        host -> recalculateBandwidthLimits = 0;
+        host -> mtu = ENET_HOST_DEFAULT_MTU;
+        host -> peerCount = peerCount;
+        host -> commandCount = 0;
+        host -> bufferCount = 0;
+        host -> checksum = NULL;
+        host -> receivedAddress.host = ENET_HOST_ANY;
+        host -> receivedAddress.port = 0;
+        host -> receivedData = NULL;
+        host -> receivedDataLength = 0;
+
+        host -> totalSentData = 0;
+        host -> totalSentPackets = 0;
+        host -> totalReceivedData = 0;
+        host -> totalReceivedPackets = 0;
+
+        host -> connectedPeers = 0;
+        host -> bandwidthLimitedPeers = 0;
+        host -> duplicatePeers = ENET_PROTOCOL_MAXIMUM_PEER_ID;
+        host -> maximumPacketSize = ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE;
+        host -> maximumWaitingData = ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA;
+
+        host -> compressor.context = NULL;
+        host -> compressor.compress = NULL;
+        host -> compressor.decompress = NULL;
+        host -> compressor.destroy = NULL;
+
+        host -> intercept = NULL;
+
+        enet_list_clear (& host -> dispatchQueue);
+
+        for (currentPeer = host -> peers;
+             currentPeer < & host -> peers [host -> peerCount];
+             ++ currentPeer)
+        {
+           currentPeer -> host = host;
+           currentPeer -> incomingPeerID = currentPeer - host -> peers;
+           currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF;
+           currentPeer -> data = NULL;
+
+           enet_list_clear (& currentPeer -> acknowledgements);
+           enet_list_clear (& currentPeer -> sentReliableCommands);
+           enet_list_clear (& currentPeer -> sentUnreliableCommands);
+           enet_list_clear (& currentPeer -> outgoingReliableCommands);
+           enet_list_clear (& currentPeer -> outgoingUnreliableCommands);
+           enet_list_clear (& currentPeer -> dispatchedCommands);
+
+           enet_peer_reset (currentPeer);
+        }
+
+        return host;
+    }
+
+    /** Destroys the host and all resources associated with it.
+        @param host pointer to the host to destroy
+    */
+    void
+    enet_host_destroy (ENetHost * host)
+    {
+        ENetPeer * currentPeer;
+
+        if (host == NULL)
+          return;
+
+        enet_socket_destroy (host -> socket);
+
+        for (currentPeer = host -> peers;
+             currentPeer < & host -> peers [host -> peerCount];
+             ++ currentPeer)
+        {
+           enet_peer_reset (currentPeer);
+        }
+
+        if (host -> compressor.context != NULL && host -> compressor.destroy)
+          (* host -> compressor.destroy) (host -> compressor.context);
+
+        enet_free (host -> peers);
+        enet_free (host);
+    }
+
+    /** Initiates a connection to a foreign host.
+        @param host host seeking the connection
+        @param address destination for the connection
+        @param channelCount number of channels to allocate
+        @param data user data supplied to the receiving host
+        @returns a peer representing the foreign host on success, NULL on failure
+        @remarks The peer returned will have not completed the connection until enet_host_service()
+        notifies of an ENET_EVENT_TYPE_CONNECT event for the peer.
+    */
+    ENetPeer *
+    enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data)
+    {
+        ENetPeer * currentPeer;
+        ENetChannel * channel;
+        ENetProtocol command;
+
+        if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
+          channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
+        else
+        if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
+          channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
+
+        for (currentPeer = host -> peers;
+             currentPeer < & host -> peers [host -> peerCount];
+             ++ currentPeer)
+        {
+           if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED)
+             break;
+        }
+
+        if (currentPeer >= & host -> peers [host -> peerCount])
+          return NULL;
+
+        currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel));
+        if (currentPeer -> channels == NULL)
+          return NULL;
+        currentPeer -> channelCount = channelCount;
+        currentPeer -> state = ENET_PEER_STATE_CONNECTING;
+        currentPeer -> address = * address;
+        currentPeer -> connectID = ++ host -> randomSeed;
+
+        if (host -> outgoingBandwidth == 0)
+          currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+        else
+          currentPeer -> windowSize = (host -> outgoingBandwidth /
+                                        ENET_PEER_WINDOW_SIZE_SCALE) *
+                                          ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+
+        if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
+          currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+        else
+        if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
+          currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+
+        for (channel = currentPeer -> channels;
+             channel < & currentPeer -> channels [channelCount];
+             ++ channel)
+        {
+            channel -> outgoingReliableSequenceNumber = 0;
+            channel -> outgoingUnreliableSequenceNumber = 0;
+            channel -> incomingReliableSequenceNumber = 0;
+            channel -> incomingUnreliableSequenceNumber = 0;
+
+            enet_list_clear (& channel -> incomingReliableCommands);
+            enet_list_clear (& channel -> incomingUnreliableCommands);
+
+            channel -> usedReliableWindows = 0;
+            memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows));
+        }
+
+        command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+        command.header.channelID = 0xFF;
+        command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID);
+        command.connect.incomingSessionID = currentPeer -> incomingSessionID;
+        command.connect.outgoingSessionID = currentPeer -> outgoingSessionID;
+        command.connect.mtu = ENET_HOST_TO_NET_32 (currentPeer -> mtu);
+        command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize);
+        command.connect.channelCount = ENET_HOST_TO_NET_32 (channelCount);
+        command.connect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth);
+        command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
+        command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval);
+        command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration);
+        command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration);
+        command.connect.connectID = currentPeer -> connectID;
+        command.connect.data = ENET_HOST_TO_NET_32 (data);
+
+        enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0);
+
+        return currentPeer;
+    }
+
+    /** Queues a packet to be sent to all peers associated with the host.
+        @param host host on which to broadcast the packet
+        @param channelID channel on which to broadcast
+        @param packet packet to broadcast
+    */
+    void
+    enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet)
+    {
+        ENetPeer * currentPeer;
+
+        for (currentPeer = host -> peers;
+             currentPeer < & host -> peers [host -> peerCount];
+             ++ currentPeer)
+        {
+           if (currentPeer -> state != ENET_PEER_STATE_CONNECTED)
+             continue;
+
+           enet_peer_send (currentPeer, channelID, packet);
+        }
+
+        if (packet -> referenceCount == 0)
+          enet_packet_destroy (packet);
+    }
+
+    /** Sets the packet compressor the host should use to compress and decompress packets.
+        @param host host to enable or disable compression for
+        @param compressor callbacks for for the packet compressor; if NULL, then compression is disabled
+    */
+    void
+    enet_host_compress (ENetHost * host, const ENetCompressor * compressor)
+    {
+        if (host -> compressor.context != NULL && host -> compressor.destroy)
+          (* host -> compressor.destroy) (host -> compressor.context);
+
+        if (compressor)
+          host -> compressor = * compressor;
+        else
+          host -> compressor.context = NULL;
+    }
+
+    /** Limits the maximum allowed channels of future incoming connections.
+        @param host host to limit
+        @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
+    */
+    void
+    enet_host_channel_limit (ENetHost * host, size_t channelLimit)
+    {
+        if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
+          channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
+        else
+        if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
+          channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
+
+        host -> channelLimit = channelLimit;
+    }
+
+
+    /** Adjusts the bandwidth limits of a host.
+        @param host host to adjust
+        @param incomingBandwidth new incoming bandwidth
+        @param outgoingBandwidth new outgoing bandwidth
+        @remarks the incoming and outgoing bandwidth parameters are identical in function to those
+        specified in enet_host_create().
+    */
+    void
+    enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
+    {
+        host -> incomingBandwidth = incomingBandwidth;
+        host -> outgoingBandwidth = outgoingBandwidth;
+        host -> recalculateBandwidthLimits = 1;
+    }
+
+    void
+    enet_host_bandwidth_throttle (ENetHost * host)
+    {
+        enet_uint32 timeCurrent = enet_time_get (),
+               elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch,
+               peersRemaining = (enet_uint32) host -> connectedPeers,
+               dataTotal = ~0,
+               bandwidth = ~0,
+               throttle = 0,
+               bandwidthLimit = 0;
+        int needsAdjustment = host -> bandwidthLimitedPeers > 0 ? 1 : 0;
+        ENetPeer * peer;
+        ENetProtocol command;
+
+        if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL)
+          return;
+
+        host -> bandwidthThrottleEpoch = timeCurrent;
+
+        if (peersRemaining == 0)
+          return;
+
+        if (host -> outgoingBandwidth != 0)
+        {
+            dataTotal = 0;
+            bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000;
+
+            for (peer = host -> peers;
+                 peer < & host -> peers [host -> peerCount];
+                ++ peer)
+            {
+                if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
+                  continue;
+
+                dataTotal += peer -> outgoingDataTotal;
+            }
+        }
+
+        while (peersRemaining > 0 && needsAdjustment != 0)
+        {
+            needsAdjustment = 0;
+
+            if (dataTotal <= bandwidth)
+              throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
+            else
+              throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
+
+            for (peer = host -> peers;
+                 peer < & host -> peers [host -> peerCount];
+                 ++ peer)
+            {
+                enet_uint32 peerBandwidth;
+
+                if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
+                    peer -> incomingBandwidth == 0 ||
+                    peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
+                  continue;
+
+                peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000;
+                if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth)
+                  continue;
+
+                peer -> packetThrottleLimit = (peerBandwidth *
+                                                ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal;
+
+                if (peer -> packetThrottleLimit == 0)
+                  peer -> packetThrottleLimit = 1;
+
+                if (peer -> packetThrottle > peer -> packetThrottleLimit)
+                  peer -> packetThrottle = peer -> packetThrottleLimit;
+
+                peer -> outgoingBandwidthThrottleEpoch = timeCurrent;
+
+                peer -> incomingDataTotal = 0;
+                peer -> outgoingDataTotal = 0;
+
+                needsAdjustment = 1;
+                -- peersRemaining;
+                bandwidth -= peerBandwidth;
+                dataTotal -= peerBandwidth;
+            }
+        }
+
+        if (peersRemaining > 0)
+        {
+            if (dataTotal <= bandwidth)
+              throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
+            else
+              throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
+
+            for (peer = host -> peers;
+                 peer < & host -> peers [host -> peerCount];
+                 ++ peer)
+            {
+                if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
+                    peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
+                  continue;
+
+                peer -> packetThrottleLimit = throttle;
+
+                if (peer -> packetThrottle > peer -> packetThrottleLimit)
+                  peer -> packetThrottle = peer -> packetThrottleLimit;
+
+                peer -> incomingDataTotal = 0;
+                peer -> outgoingDataTotal = 0;
+            }
+        }
+
+        if (host -> recalculateBandwidthLimits)
+        {
+           host -> recalculateBandwidthLimits = 0;
+
+           peersRemaining = (enet_uint32) host -> connectedPeers;
+           bandwidth = host -> incomingBandwidth;
+           needsAdjustment = 1;
+
+           if (bandwidth == 0)
+             bandwidthLimit = 0;
+           else
+           while (peersRemaining > 0 && needsAdjustment != 0)
+           {
+               needsAdjustment = 0;
+               bandwidthLimit = bandwidth / peersRemaining;
+
+               for (peer = host -> peers;
+                    peer < & host -> peers [host -> peerCount];
+                    ++ peer)
+               {
+                   if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
+                       peer -> incomingBandwidthThrottleEpoch == timeCurrent)
+                     continue;
+
+                   if (peer -> outgoingBandwidth > 0 &&
+                       peer -> outgoingBandwidth >= bandwidthLimit)
+                     continue;
+
+                   peer -> incomingBandwidthThrottleEpoch = timeCurrent;
+
+                   needsAdjustment = 1;
+                   -- peersRemaining;
+                   bandwidth -= peer -> outgoingBandwidth;
+               }
+           }
+
+           for (peer = host -> peers;
+                peer < & host -> peers [host -> peerCount];
+                ++ peer)
+           {
+               if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
+                 continue;
+
+               command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+               command.header.channelID = 0xFF;
+               command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
+
+               if (peer -> incomingBandwidthThrottleEpoch == timeCurrent)
+                 command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth);
+               else
+                 command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit);
+
+               enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
+           }
+        }
+    }
+
+    /** @} */
+
+    // @from_file: list.c
+    /**
+     @file list.c
+     @brief ENet linked list functions
+    */
+    #define ENET_BUILDING_LIB 1
+
+
+    /**
+        @defgroup list ENet linked list utility functions
+        @ingroup private
+        @{
+    */
+    void
+    enet_list_clear (ENetList * list)
+    {
+       list -> sentinel.next = & list -> sentinel;
+       list -> sentinel.previous = & list -> sentinel;
+    }
+
+    ENetListIterator
+    enet_list_insert (ENetListIterator position, void * data)
+    {
+       ENetListIterator result = (ENetListIterator) data;
+
+       result -> previous = position -> previous;
+       result -> next = position;
+
+       result -> previous -> next = result;
+       position -> previous = result;
+
+       return result;
+    }
+
+    void *
+    enet_list_remove (ENetListIterator position)
+    {
+       position -> previous -> next = position -> next;
+       position -> next -> previous = position -> previous;
+
+       return position;
+    }
+
+    ENetListIterator
+    enet_list_move (ENetListIterator position, void * dataFirst, void * dataLast)
+    {
+       ENetListIterator first = (ENetListIterator) dataFirst,
+                        last = (ENetListIterator) dataLast;
+
+       first -> previous -> next = last -> next;
+       last -> next -> previous = first -> previous;
+
+       first -> previous = position -> previous;
+       last -> next = position;
+
+       first -> previous -> next = first;
+       position -> previous = last;
+
+       return first;
+    }
+
+    size_t
+    enet_list_size (ENetList * list)
+    {
+       size_t size = 0;
+       ENetListIterator position;
+
+       for (position = enet_list_begin (list);
+            position != enet_list_end (list);
+            position = enet_list_next (position))
+         ++ size;
+
+       return size;
+    }
+
+    /** @} */
+
+    // @from_file: packet.c
+    /**
+     @file  packet.c
+     @brief ENet packet management functions
+    */
+
+    #define ENET_BUILDING_LIB 1
+
+
+    /** @defgroup Packet ENet packet functions
+        @{
+    */
+
+    /** Creates a packet that may be sent to a peer.
+        @param data         initial contents of the packet's data; the packet's data will remain uninitialized if data is NULL.
+        @param dataLength   size of the data allocated for this packet
+        @param flags        flags for this packet as described for the ENetPacket structure.
+        @returns the packet on success, NULL on failure
+    */
+    ENetPacket *
+    enet_packet_create (const void * data, size_t dataLength, enet_uint32 flags)
+    {
+        ENetPacket * packet = (ENetPacket *) enet_malloc (sizeof (ENetPacket));
+        if (packet == NULL)
+          return NULL;
+
+        if (flags & ENET_PACKET_FLAG_NO_ALLOCATE)
+          packet -> data = (enet_uint8 *) data;
+        else
+        if (dataLength <= 0)
+          packet -> data = NULL;
+        else
+        {
+           packet -> data = (enet_uint8 *) enet_malloc (dataLength);
+           if (packet -> data == NULL)
+           {
+              enet_free (packet);
+              return NULL;
+           }
+
+           if (data != NULL)
+             memcpy (packet -> data, data, dataLength);
+        }
+
+        packet -> referenceCount = 0;
+        packet -> flags = flags;
+        packet -> dataLength = dataLength;
+        packet -> freeCallback = NULL;
+        packet -> userData = NULL;
+
+        return packet;
+    }
+
+    /** Destroys the packet and deallocates its data.
+        @param packet packet to be destroyed
+    */
+    void
+    enet_packet_destroy (ENetPacket * packet)
+    {
+        if (packet == NULL)
+          return;
+
+        if (packet -> freeCallback != NULL)
+          (* packet -> freeCallback) (packet);
+        if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE) &&
+            packet -> data != NULL)
+          enet_free (packet -> data);
+        enet_free (packet);
+    }
+
+    /** Attempts to resize the data in the packet to length specified in the
+        dataLength parameter
+        @param packet packet to resize
+        @param dataLength new size for the packet data
+        @returns 0 on success, < 0 on failure
+    */
+    int
+    enet_packet_resize (ENetPacket * packet, size_t dataLength)
+    {
+        enet_uint8 * newData;
+
+        if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE))
+        {
+           packet -> dataLength = dataLength;
+
+           return 0;
+        }
+
+        newData = (enet_uint8 *) enet_malloc (dataLength);
+        if (newData == NULL)
+          return -1;
+
+        memcpy (newData, packet -> data, packet -> dataLength);
+        enet_free (packet -> data);
+
+        packet -> data = newData;
+        packet -> dataLength = dataLength;
+
+        return 0;
+    }
+
+    static int initializedCRC32 = 0;
+    static enet_uint32 crcTable [256];
+
+    static enet_uint32
+    reflect_crc (int val, int bits)
+    {
+        int result = 0, bit;
+
+        for (bit = 0; bit < bits; bit ++)
+        {
+            if(val & 1) result |= 1 << (bits - 1 - bit);
+            val >>= 1;
+        }
+
+        return result;
+    }
+
+    static void
+    initialize_crc32 (void)
+    {
+        int byte;
+
+        for (byte = 0; byte < 256; ++ byte)
+        {
+            enet_uint32 crc = reflect_crc (byte, 8) << 24;
+            int offset;
+
+            for(offset = 0; offset < 8; ++ offset)
+            {
+                if (crc & 0x80000000)
+                    crc = (crc << 1) ^ 0x04c11db7;
+                else
+                    crc <<= 1;
+            }
+
+            crcTable [byte] = reflect_crc (crc, 32);
+        }
+
+        initializedCRC32 = 1;
+    }
+
+    enet_uint32
+    enet_crc32 (const ENetBuffer * buffers, size_t bufferCount)
+    {
+        enet_uint32 crc = 0xFFFFFFFF;
+
+        if (! initializedCRC32) initialize_crc32 ();
+
+        while (bufferCount -- > 0)
+        {
+            const enet_uint8 * data = (const enet_uint8 *) buffers -> data,
+                             * dataEnd = & data [buffers -> dataLength];
+
+            while (data < dataEnd)
+            {
+                crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++];
+            }
+
+            ++ buffers;
+        }
+
+        return ENET_HOST_TO_NET_32 (~ crc);
+    }
+
+    /** @} */
+
+    // @from_file: peer.c
+    /**
+     @file  peer.c
+     @brief ENet peer management functions
+    */
+
+    #define ENET_BUILDING_LIB 1
+
+
+    /** @defgroup peer ENet peer functions
+        @{
+    */
+
+    /** Configures throttle parameter for a peer.
+
+        Unreliable packets are dropped by ENet in response to the varying conditions
+        of the Internet connection to the peer.  The throttle represents a probability
+        that an unreliable packet should not be dropped and thus sent by ENet to the peer.
+        The lowest mean round trip time from the sending of a reliable packet to the
+        receipt of its acknowledgement is measured over an amount of time specified by
+        the interval parameter in milliseconds.  If a measured round trip time happens to
+        be significantly less than the mean round trip time measured over the interval,
+        then the throttle probability is increased to allow more traffic by an amount
+        specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE
+        constant.  If a measured round trip time happens to be significantly greater than
+        the mean round trip time measured over the interval, then the throttle probability
+        is decreased to limit traffic by an amount specified in the deceleration parameter, which
+        is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant.  When the throttle has
+        a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by
+        ENet, and so 100% of all unreliable packets will be sent.  When the throttle has a
+        value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable
+        packets will be sent.  Intermediate values for the throttle represent intermediate
+        probabilities between 0% and 100% of unreliable packets being sent.  The bandwidth
+        limits of the local and foreign hosts are taken into account to determine a
+        sensible limit for the throttle probability above which it should not raise even in
+        the best of conditions.
+
+        @param peer peer to configure
+        @param interval interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL.
+        @param acceleration rate at which to increase the throttle probability as mean RTT declines
+        @param deceleration rate at which to decrease the throttle probability as mean RTT increases
+    */
+    void
+    enet_peer_throttle_configure (ENetPeer * peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deceleration)
+    {
+        ENetProtocol command;
+
+        peer -> packetThrottleInterval = interval;
+        peer -> packetThrottleAcceleration = acceleration;
+        peer -> packetThrottleDeceleration = deceleration;
+
+        command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+        command.header.channelID = 0xFF;
+
+        command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32 (interval);
+        command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (acceleration);
+        command.throttleConfigure.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (deceleration);
+
+        enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
+    }
+
+    int
+    enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt)
+    {
+        if (peer -> lastRoundTripTime <= peer -> lastRoundTripTimeVariance)
+        {
+            peer -> packetThrottle = peer -> packetThrottleLimit;
+        }
+        else
+        if (rtt < peer -> lastRoundTripTime)
+        {
+            peer -> packetThrottle += peer -> packetThrottleAcceleration;
+
+            if (peer -> packetThrottle > peer -> packetThrottleLimit)
+              peer -> packetThrottle = peer -> packetThrottleLimit;
+
+            return 1;
+        }
+        else
+        if (rtt > peer -> lastRoundTripTime + 2 * peer -> lastRoundTripTimeVariance)
+        {
+            if (peer -> packetThrottle > peer -> packetThrottleDeceleration)
+              peer -> packetThrottle -= peer -> packetThrottleDeceleration;
+            else
+              peer -> packetThrottle = 0;
+
+            return -1;
+        }
+
+        return 0;
+    }
+
+    /** Queues a packet to be sent.
+        @param peer destination for the packet
+        @param channelID channel on which to send
+        @param packet packet to send
+        @retval 0 on success
+        @retval < 0 on failure
+    */
+    int
+    enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
+    {
+       ENetChannel * channel = & peer -> channels [channelID];
+       ENetProtocol command;
+       size_t fragmentLength;
+
+       if (peer -> state != ENET_PEER_STATE_CONNECTED ||
+           channelID >= peer -> channelCount ||
+           packet -> dataLength > peer -> host -> maximumPacketSize)
+         return -1;
+
+       fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment);
+       if (peer -> host -> checksum != NULL)
+         fragmentLength -= sizeof(enet_uint32);
+
+       if (packet -> dataLength > fragmentLength)
+       {
+          enet_uint32 fragmentCount = (packet -> dataLength + fragmentLength - 1) / fragmentLength,
+                 fragmentNumber,
+                 fragmentOffset;
+          enet_uint8 commandNumber;
+          enet_uint16 startSequenceNumber;
+          ENetList fragments;
+          ENetOutgoingCommand * fragment;
+
+          if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT)
+            return -1;
+
+          if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT)) == ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT &&
+              channel -> outgoingUnreliableSequenceNumber < 0xFFFF)
+          {
+             commandNumber = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT;
+             startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1);
+          }
+          else
+          {
+             commandNumber = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+             startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1);
+          }
+
+          enet_list_clear (& fragments);
+
+          for (fragmentNumber = 0,
+                 fragmentOffset = 0;
+               fragmentOffset < packet -> dataLength;
+               ++ fragmentNumber,
+                 fragmentOffset += fragmentLength)
+          {
+             if (packet -> dataLength - fragmentOffset < fragmentLength)
+               fragmentLength = packet -> dataLength - fragmentOffset;
+
+             fragment = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand));
+             if (fragment == NULL)
+             {
+                while (! enet_list_empty (& fragments))
+                {
+                   fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments));
+
+                   enet_free (fragment);
+                }
+
+                return -1;
+             }
+
+             fragment -> fragmentOffset = fragmentOffset;
+             fragment -> fragmentLength = fragmentLength;
+             fragment -> packet = packet;
+             fragment -> command.header.command = commandNumber;
+             fragment -> command.header.channelID = channelID;
+             fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber;
+             fragment -> command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength);
+             fragment -> command.sendFragment.fragmentCount = ENET_HOST_TO_NET_32 (fragmentCount);
+             fragment -> command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber);
+             fragment -> command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength);
+             fragment -> command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32 (fragmentOffset);
+
+             enet_list_insert (enet_list_end (& fragments), fragment);
+          }
+
+          packet -> referenceCount += fragmentNumber;
+
+          while (! enet_list_empty (& fragments))
+          {
+             fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments));
+
+             enet_peer_setup_outgoing_command (peer, fragment);
+          }
+
+          return 0;
+       }
+
+       command.header.channelID = channelID;
+
+       if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED)) == ENET_PACKET_FLAG_UNSEQUENCED)
+       {
+          command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
+          command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
+       }
+       else
+       if (packet -> flags & ENET_PACKET_FLAG_RELIABLE || channel -> outgoingUnreliableSequenceNumber >= 0xFFFF)
+       {
+          command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+          command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
+       }
+       else
+       {
+          command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE;
+          command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
+       }
+
+       if (enet_peer_queue_outgoing_command (peer, & command, packet, 0, packet -> dataLength) == NULL)
+         return -1;
+
+       return 0;
+    }
+
+    /** Attempts to dequeue any incoming queued packet.
+        @param peer peer to dequeue packets from
+        @param channelID holds the channel ID of the channel the packet was received on success
+        @returns a pointer to the packet, or NULL if there are no available incoming queued packets
+    */
+    ENetPacket *
+    enet_peer_receive (ENetPeer * peer, enet_uint8 * channelID)
+    {
+       ENetIncomingCommand * incomingCommand;
+       ENetPacket * packet;
+
+       if (enet_list_empty (& peer -> dispatchedCommands))
+         return NULL;
+
+       incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (& peer -> dispatchedCommands));
+
+       if (channelID != NULL)
+         * channelID = incomingCommand -> command.header.channelID;
+
+       packet = incomingCommand -> packet;
+
+       -- packet -> referenceCount;
+
+       if (incomingCommand -> fragments != NULL)
+         enet_free (incomingCommand -> fragments);
+
+       enet_free (incomingCommand);
+
+       peer -> totalWaitingData -= packet -> dataLength;
+
+       return packet;
+    }
+
+    static void
+    enet_peer_reset_outgoing_commands (ENetList * queue)
+    {
+        ENetOutgoingCommand * outgoingCommand;
+
+        while (! enet_list_empty (queue))
+        {
+           outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (queue));
+
+           if (outgoingCommand -> packet != NULL)
+           {
+              -- outgoingCommand -> packet -> referenceCount;
+
+              if (outgoingCommand -> packet -> referenceCount == 0)
+                enet_packet_destroy (outgoingCommand -> packet);
+           }
+
+           enet_free (outgoingCommand);
+        }
+    }
+
+    static void
+    enet_peer_remove_incoming_commands (ENetList * queue, ENetListIterator startCommand, ENetListIterator endCommand)
+    {
+        ENetListIterator currentCommand;
+
+        for (currentCommand = startCommand; currentCommand != endCommand; )
+        {
+           ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
+
+           currentCommand = enet_list_next (currentCommand);
+
+           enet_list_remove (& incomingCommand -> incomingCommandList);
+
+           if (incomingCommand -> packet != NULL)
+           {
+              -- incomingCommand -> packet -> referenceCount;
+
+              if (incomingCommand -> packet -> referenceCount == 0)
+                enet_packet_destroy (incomingCommand -> packet);
+           }
+
+           if (incomingCommand -> fragments != NULL)
+             enet_free (incomingCommand -> fragments);
+
+           enet_free (incomingCommand);
+        }
+    }
+
+    static void
+    enet_peer_reset_incoming_commands (ENetList * queue)
+    {
+        enet_peer_remove_incoming_commands(queue, enet_list_begin (queue), enet_list_end (queue));
+    }
+
+    void
+    enet_peer_reset_queues (ENetPeer * peer)
+    {
+        ENetChannel * channel;
+
+        if (peer -> needsDispatch)
+        {
+           enet_list_remove (& peer -> dispatchList);
+
+           peer -> needsDispatch = 0;
+        }
+
+        while (! enet_list_empty (& peer -> acknowledgements))
+          enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements)));
+
+        enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands);
+        enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands);
+        enet_peer_reset_outgoing_commands (& peer -> outgoingReliableCommands);
+        enet_peer_reset_outgoing_commands (& peer -> outgoingUnreliableCommands);
+        enet_peer_reset_incoming_commands (& peer -> dispatchedCommands);
+
+        if (peer -> channels != NULL && peer -> channelCount > 0)
+        {
+            for (channel = peer -> channels;
+                 channel < & peer -> channels [peer -> channelCount];
+                 ++ channel)
+            {
+                enet_peer_reset_incoming_commands (& channel -> incomingReliableCommands);
+                enet_peer_reset_incoming_commands (& channel -> incomingUnreliableCommands);
+            }
+
+            enet_free (peer -> channels);
+        }
+
+        peer -> channels = NULL;
+        peer -> channelCount = 0;
+    }
+
+    void
+    enet_peer_on_connect (ENetPeer * peer)
+    {
+        if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
+        {
+            if (peer -> incomingBandwidth != 0)
+              ++ peer -> host -> bandwidthLimitedPeers;
+
+            ++ peer -> host -> connectedPeers;
+        }
+    }
+
+    void
+    enet_peer_on_disconnect (ENetPeer * peer)
+    {
+        if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER)
+        {
+            if (peer -> incomingBandwidth != 0)
+              -- peer -> host -> bandwidthLimitedPeers;
+
+            -- peer -> host -> connectedPeers;
+        }
+    }
+
+    /** Forcefully disconnects a peer.
+        @param peer peer to forcefully disconnect
+        @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout
+        on its connection to the local host.
+    */
+    void
+    enet_peer_reset (ENetPeer * peer)
+    {
+        enet_peer_on_disconnect (peer);
+
+        peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID;
+        peer -> connectID = 0;
+
+        peer -> state = ENET_PEER_STATE_DISCONNECTED;
+
+        peer -> incomingBandwidth = 0;
+        peer -> outgoingBandwidth = 0;
+        peer -> incomingBandwidthThrottleEpoch = 0;
+        peer -> outgoingBandwidthThrottleEpoch = 0;
+        peer -> incomingDataTotal = 0;
+        peer -> outgoingDataTotal = 0;
+        peer -> lastSendTime = 0;
+        peer -> lastReceiveTime = 0;
+        peer -> nextTimeout = 0;
+        peer -> earliestTimeout = 0;
+        peer -> packetLossEpoch = 0;
+        peer -> packetsSent = 0;
+        peer -> packetsLost = 0;
+        peer -> packetLoss = 0;
+        peer -> packetLossVariance = 0;
+        peer -> packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE;
+        peer -> packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE;
+        peer -> packetThrottleCounter = 0;
+        peer -> packetThrottleEpoch = 0;
+        peer -> packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION;
+        peer -> packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION;
+        peer -> packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL;
+        peer -> pingInterval = ENET_PEER_PING_INTERVAL;
+        peer -> timeoutLimit = ENET_PEER_TIMEOUT_LIMIT;
+        peer -> timeoutMinimum = ENET_PEER_TIMEOUT_MINIMUM;
+        peer -> timeoutMaximum = ENET_PEER_TIMEOUT_MAXIMUM;
+        peer -> lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
+        peer -> lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
+        peer -> lastRoundTripTimeVariance = 0;
+        peer -> highestRoundTripTimeVariance = 0;
+        peer -> roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
+        peer -> roundTripTimeVariance = 0;
+        peer -> mtu = peer -> host -> mtu;
+        peer -> reliableDataInTransit = 0;
+        peer -> outgoingReliableSequenceNumber = 0;
+        peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+        peer -> incomingUnsequencedGroup = 0;
+        peer -> outgoingUnsequencedGroup = 0;
+        peer -> eventData = 0;
+        peer -> totalWaitingData = 0;
+
+        memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow));
+
+        enet_peer_reset_queues (peer);
+    }
+
+    /** Sends a ping request to a peer.
+        @param peer destination for the ping request
+        @remarks ping requests factor into the mean round trip time as designated by the
+        roundTripTime field in the ENetPeer structure.  ENet automatically pings all connected
+        peers at regular intervals, however, this function may be called to ensure more
+        frequent ping requests.
+    */
+    void
+    enet_peer_ping (ENetPeer * peer)
+    {
+        ENetProtocol command;
+
+        if (peer -> state != ENET_PEER_STATE_CONNECTED)
+          return;
+
+        command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+        command.header.channelID = 0xFF;
+
+        enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
+    }
+
+    /** Sets the interval at which pings will be sent to a peer.
+
+        Pings are used both to monitor the liveness of the connection and also to dynamically
+        adjust the throttle during periods of low traffic so that the throttle has reasonable
+        responsiveness during traffic spikes.
+
+        @param peer the peer to adjust
+        @param pingInterval the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0
+    */
+    void
+    enet_peer_ping_interval (ENetPeer * peer, enet_uint32 pingInterval)
+    {
+        peer -> pingInterval = pingInterval ? pingInterval : ENET_PEER_PING_INTERVAL;
+    }
+
+    /** Sets the timeout parameters for a peer.
+
+        The timeout parameter control how and when a peer will timeout from a failure to acknowledge
+        reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable
+        packet is not acknowledge within some multiple of the average RTT plus a variance tolerance,
+        the timeout will be doubled until it reaches a set limit. If the timeout is thus at this
+        limit and reliable packets have been sent but not acknowledged within a certain minimum time
+        period, the peer will be disconnected. Alternatively, if reliable packets have been sent
+        but not acknowledged for a certain maximum time period, the peer will be disconnected regardless
+        of the current timeout limit value.
+
+        @param peer the peer to adjust
+        @param timeoutLimit the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0
+        @param timeoutMinimum the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0
+        @param timeoutMaximum the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0
+    */
+
+    void
+    enet_peer_timeout (ENetPeer * peer, enet_uint32 timeoutLimit, enet_uint32 timeoutMinimum, enet_uint32 timeoutMaximum)
+    {
+        peer -> timeoutLimit = timeoutLimit ? timeoutLimit : ENET_PEER_TIMEOUT_LIMIT;
+        peer -> timeoutMinimum = timeoutMinimum ? timeoutMinimum : ENET_PEER_TIMEOUT_MINIMUM;
+        peer -> timeoutMaximum = timeoutMaximum ? timeoutMaximum : ENET_PEER_TIMEOUT_MAXIMUM;
+    }
+
+    /** Force an immediate disconnection from a peer.
+        @param peer peer to disconnect
+        @param data data describing the disconnection
+        @remarks No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not
+        guaranteed to receive the disconnect notification, and is reset immediately upon
+        return from this function.
+    */
+    void
+    enet_peer_disconnect_now (ENetPeer * peer, enet_uint32 data)
+    {
+        ENetProtocol command;
+
+        if (peer -> state == ENET_PEER_STATE_DISCONNECTED)
+          return;
+
+        if (peer -> state != ENET_PEER_STATE_ZOMBIE &&
+            peer -> state != ENET_PEER_STATE_DISCONNECTING)
+        {
+            enet_peer_reset_queues (peer);
+
+            command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
+            command.header.channelID = 0xFF;
+            command.disconnect.data = ENET_HOST_TO_NET_32 (data);
+
+            enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
+
+            enet_host_flush (peer -> host);
+        }
+
+        enet_peer_reset (peer);
+    }
+
+    /** Request a disconnection from a peer.
+        @param peer peer to request a disconnection
+        @param data data describing the disconnection
+        @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service()
+        once the disconnection is complete.
+    */
+    void
+    enet_peer_disconnect (ENetPeer * peer, enet_uint32 data)
+    {
+        ENetProtocol command;
+
+        if (peer -> state == ENET_PEER_STATE_DISCONNECTING ||
+            peer -> state == ENET_PEER_STATE_DISCONNECTED ||
+            peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT ||
+            peer -> state == ENET_PEER_STATE_ZOMBIE)
+          return;
+
+        enet_peer_reset_queues (peer);
+
+        command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT;
+        command.header.channelID = 0xFF;
+        command.disconnect.data = ENET_HOST_TO_NET_32 (data);
+
+        if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER)
+          command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+        else
+          command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
+
+        enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
+
+        if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER)
+        {
+            enet_peer_on_disconnect (peer);
+
+            peer -> state = ENET_PEER_STATE_DISCONNECTING;
+        }
+        else
+        {
+            enet_host_flush (peer -> host);
+            enet_peer_reset (peer);
+        }
+    }
+
+    /** Request a disconnection from a peer, but only after all queued outgoing packets are sent.
+        @param peer peer to request a disconnection
+        @param data data describing the disconnection
+        @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service()
+        once the disconnection is complete.
+    */
+    void
+    enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data)
+    {
+        if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) &&
+            ! (enet_list_empty (& peer -> outgoingReliableCommands) &&
+               enet_list_empty (& peer -> outgoingUnreliableCommands) &&
+               enet_list_empty (& peer -> sentReliableCommands)))
+        {
+            peer -> state = ENET_PEER_STATE_DISCONNECT_LATER;
+            peer -> eventData = data;
+        }
+        else
+          enet_peer_disconnect (peer, data);
+    }
+
+    ENetAcknowledgement *
+    enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, enet_uint16 sentTime)
+    {
+        ENetAcknowledgement * acknowledgement;
+
+        if (command -> header.channelID < peer -> channelCount)
+        {
+            ENetChannel * channel = & peer -> channels [command -> header.channelID];
+            enet_uint16 reliableWindow = command -> header.reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE,
+                        currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+
+            if (command -> header.reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+               reliableWindow += ENET_PEER_RELIABLE_WINDOWS;
+
+            if (reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1 && reliableWindow <= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS)
+              return NULL;
+        }
+
+        acknowledgement = (ENetAcknowledgement *) enet_malloc (sizeof (ENetAcknowledgement));
+        if (acknowledgement == NULL)
+          return NULL;
+
+        peer -> outgoingDataTotal += sizeof (ENetProtocolAcknowledge);
+
+        acknowledgement -> sentTime = sentTime;
+        acknowledgement -> command = * command;
+
+        enet_list_insert (enet_list_end (& peer -> acknowledgements), acknowledgement);
+
+        return acknowledgement;
+    }
+
+    void
+    enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand)
+    {
+        ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID];
+
+        peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength;
+
+        if (outgoingCommand -> command.header.channelID == 0xFF)
+        {
+           ++ peer -> outgoingReliableSequenceNumber;
+
+           outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber;
+           outgoingCommand -> unreliableSequenceNumber = 0;
+        }
+        else
+        if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
+        {
+           ++ channel -> outgoingReliableSequenceNumber;
+           channel -> outgoingUnreliableSequenceNumber = 0;
+
+           outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
+           outgoingCommand -> unreliableSequenceNumber = 0;
+        }
+        else
+        if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED)
+        {
+           ++ peer -> outgoingUnsequencedGroup;
+
+           outgoingCommand -> reliableSequenceNumber = 0;
+           outgoingCommand -> unreliableSequenceNumber = 0;
+        }
+        else
+        {
+           if (outgoingCommand -> fragmentOffset == 0)
+             ++ channel -> outgoingUnreliableSequenceNumber;
+
+           outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
+           outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber;
+        }
+
+        outgoingCommand -> sendAttempts = 0;
+        outgoingCommand -> sentTime = 0;
+        outgoingCommand -> roundTripTimeout = 0;
+        outgoingCommand -> roundTripTimeoutLimit = 0;
+        outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber);
+
+        switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK)
+        {
+        case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
+            outgoingCommand -> command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> unreliableSequenceNumber);
+            break;
+
+        case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
+            outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup);
+            break;
+
+        default:
+            break;
+        }
+
+        if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
+          enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
+        else
+          enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand);
+    }
+
+    ENetOutgoingCommand *
+    enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 offset, enet_uint16 length)
+    {
+        ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand));
+        if (outgoingCommand == NULL)
+          return NULL;
+
+        outgoingCommand -> command = * command;
+        outgoingCommand -> fragmentOffset = offset;
+        outgoingCommand -> fragmentLength = length;
+        outgoingCommand -> packet = packet;
+        if (packet != NULL)
+          ++ packet -> referenceCount;
+
+        enet_peer_setup_outgoing_command (peer, outgoingCommand);
+
+        return outgoingCommand;
+    }
+
+    void
+    enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel)
+    {
+        ENetListIterator droppedCommand, startCommand, currentCommand;
+
+        for (droppedCommand = startCommand = currentCommand = enet_list_begin (& channel -> incomingUnreliableCommands);
+             currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
+             currentCommand = enet_list_next (currentCommand))
+        {
+           ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
+
+           if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED)
+             continue;
+
+           if (incomingCommand -> reliableSequenceNumber == channel -> incomingReliableSequenceNumber)
+           {
+              if (incomingCommand -> fragmentsRemaining <= 0)
+              {
+                 channel -> incomingUnreliableSequenceNumber = incomingCommand -> unreliableSequenceNumber;
+                 continue;
+              }
+
+              if (startCommand != currentCommand)
+              {
+                 enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand));
+
+                 if (! peer -> needsDispatch)
+                 {
+                    enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
+
+                    peer -> needsDispatch = 1;
+                 }
+
+                 droppedCommand = currentCommand;
+              }
+              else
+              if (droppedCommand != currentCommand)
+                droppedCommand = enet_list_previous (currentCommand);
+           }
+           else
+           {
+              enet_uint16 reliableWindow = incomingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE,
+                          currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+              if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+                reliableWindow += ENET_PEER_RELIABLE_WINDOWS;
+              if (reliableWindow >= currentWindow && reliableWindow < currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1)
+                break;
+
+              droppedCommand = enet_list_next (currentCommand);
+
+              if (startCommand != currentCommand)
+              {
+                 enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand));
+
+                 if (! peer -> needsDispatch)
+                 {
+                    enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
+
+                    peer -> needsDispatch = 1;
+                 }
+              }
+           }
+
+           startCommand = enet_list_next (currentCommand);
+        }
+
+        if (startCommand != currentCommand)
+        {
+           enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand));
+
+           if (! peer -> needsDispatch)
+           {
+               enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
+
+               peer -> needsDispatch = 1;
+           }
+
+           droppedCommand = currentCommand;
+        }
+
+        enet_peer_remove_incoming_commands (& channel -> incomingUnreliableCommands, enet_list_begin (& channel -> incomingUnreliableCommands), droppedCommand);
+    }
+
+    void
+    enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * channel)
+    {
+        ENetListIterator currentCommand;
+
+        for (currentCommand = enet_list_begin (& channel -> incomingReliableCommands);
+             currentCommand != enet_list_end (& channel -> incomingReliableCommands);
+             currentCommand = enet_list_next (currentCommand))
+        {
+           ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
+
+           if (incomingCommand -> fragmentsRemaining > 0 ||
+               incomingCommand -> reliableSequenceNumber != (enet_uint16) (channel -> incomingReliableSequenceNumber + 1))
+             break;
+
+           channel -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber;
+
+           if (incomingCommand -> fragmentCount > 0)
+             channel -> incomingReliableSequenceNumber += incomingCommand -> fragmentCount - 1;
+        }
+
+        if (currentCommand == enet_list_begin (& channel -> incomingReliableCommands))
+          return;
+
+        channel -> incomingUnreliableSequenceNumber = 0;
+
+        enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand));
+
+        if (! peer -> needsDispatch)
+        {
+           enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
+
+           peer -> needsDispatch = 1;
+        }
+
+        if (! enet_list_empty (& channel -> incomingUnreliableCommands))
+           enet_peer_dispatch_incoming_unreliable_commands (peer, channel);
+    }
+
+    ENetIncomingCommand *
+    enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, const void * data, size_t dataLength, enet_uint32 flags, enet_uint32 fragmentCount)
+    {
+        static ENetIncomingCommand dummyCommand;
+
+        ENetChannel * channel = & peer -> channels [command -> header.channelID];
+        enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber = 0;
+        enet_uint16 reliableWindow, currentWindow;
+        ENetIncomingCommand * incomingCommand;
+        ENetListIterator currentCommand;
+        ENetPacket * packet = NULL;
+
+        if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER)
+          goto discardCommand;
+
+        if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED)
+        {
+            reliableSequenceNumber = command -> header.reliableSequenceNumber;
+            reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+            currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+
+            if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+               reliableWindow += ENET_PEER_RELIABLE_WINDOWS;
+
+            if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1)
+              goto discardCommand;
+        }
+
+        switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK)
+        {
+        case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:
+        case ENET_PROTOCOL_COMMAND_SEND_RELIABLE:
+           if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber)
+             goto discardCommand;
+
+           for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands));
+                currentCommand != enet_list_end (& channel -> incomingReliableCommands);
+                currentCommand = enet_list_previous (currentCommand))
+           {
+              incomingCommand = (ENetIncomingCommand *) currentCommand;
+
+              if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
+              {
+                 if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+                   continue;
+              }
+              else
+              if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
+                break;
+
+              if (incomingCommand -> reliableSequenceNumber <= reliableSequenceNumber)
+              {
+                 if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber)
+                   break;
+
+                 goto discardCommand;
+              }
+           }
+           break;
+
+        case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
+        case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:
+           unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber);
+
+           if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber &&
+               unreliableSequenceNumber <= channel -> incomingUnreliableSequenceNumber)
+             goto discardCommand;
+
+           for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands));
+                currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
+                currentCommand = enet_list_previous (currentCommand))
+           {
+              incomingCommand = (ENetIncomingCommand *) currentCommand;
+
+              if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED)
+                continue;
+
+              if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
+              {
+                 if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+                   continue;
+              }
+              else
+              if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
+                break;
+
+              if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber)
+                break;
+
+              if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber)
+                continue;
+
+              if (incomingCommand -> unreliableSequenceNumber <= unreliableSequenceNumber)
+              {
+                 if (incomingCommand -> unreliableSequenceNumber < unreliableSequenceNumber)
+                   break;
+
+                 goto discardCommand;
+              }
+           }
+           break;
+
+        case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
+           currentCommand = enet_list_end (& channel -> incomingUnreliableCommands);
+           break;
+
+        default:
+           goto discardCommand;
+        }
+
+        if (peer -> totalWaitingData >= peer -> host -> maximumWaitingData)
+          goto notifyError;
+
+        packet = enet_packet_create (data, dataLength, flags);
+        if (packet == NULL)
+          goto notifyError;
+
+        incomingCommand = (ENetIncomingCommand *) enet_malloc (sizeof (ENetIncomingCommand));
+        if (incomingCommand == NULL)
+          goto notifyError;
+
+        incomingCommand -> reliableSequenceNumber = command -> header.reliableSequenceNumber;
+        incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF;
+        incomingCommand -> command = * command;
+        incomingCommand -> fragmentCount = fragmentCount;
+        incomingCommand -> fragmentsRemaining = fragmentCount;
+        incomingCommand -> packet = packet;
+        incomingCommand -> fragments = NULL;
+
+        if (fragmentCount > 0)
+        {
+           if (fragmentCount <= ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT)
+             incomingCommand -> fragments = (enet_uint32 *) enet_malloc ((fragmentCount + 31) / 32 * sizeof (enet_uint32));
+           if (incomingCommand -> fragments == NULL)
+           {
+              enet_free (incomingCommand);
+
+              goto notifyError;
+           }
+           memset (incomingCommand -> fragments, 0, (fragmentCount + 31) / 32 * sizeof (enet_uint32));
+        }
+
+        if (packet != NULL)
+        {
+           ++ packet -> referenceCount;
+
+           peer -> totalWaitingData += packet -> dataLength;
+        }
+
+        enet_list_insert (enet_list_next (currentCommand), incomingCommand);
+
+        switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK)
+        {
+        case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:
+        case ENET_PROTOCOL_COMMAND_SEND_RELIABLE:
+           enet_peer_dispatch_incoming_reliable_commands (peer, channel);
+           break;
+
+        default:
+           enet_peer_dispatch_incoming_unreliable_commands (peer, channel);
+           break;
+        }
+
+        return incomingCommand;
+
+    discardCommand:
+        if (fragmentCount > 0)
+          goto notifyError;
+
+        if (packet != NULL && packet -> referenceCount == 0)
+          enet_packet_destroy (packet);
+
+        return & dummyCommand;
+
+    notifyError:
+        if (packet != NULL && packet -> referenceCount == 0)
+          enet_packet_destroy (packet);
+
+        return NULL;
+    }
+
+    /** @} */
+
+    // @from_file: protocol.c
+    /**
+     @file  protocol.c
+     @brief ENet protocol functions
+    */
+    #include <stdio.h>
+
+    #define ENET_BUILDING_LIB 1
+
+
+
+
+    static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] =
+    {
+        0,
+        sizeof (ENetProtocolAcknowledge),
+        sizeof (ENetProtocolConnect),
+        sizeof (ENetProtocolVerifyConnect),
+        sizeof (ENetProtocolDisconnect),
+        sizeof (ENetProtocolPing),
+        sizeof (ENetProtocolSendReliable),
+        sizeof (ENetProtocolSendUnreliable),
+        sizeof (ENetProtocolSendFragment),
+        sizeof (ENetProtocolSendUnsequenced),
+        sizeof (ENetProtocolBandwidthLimit),
+        sizeof (ENetProtocolThrottleConfigure),
+        sizeof (ENetProtocolSendFragment)
+    };
+
+    size_t
+    enet_protocol_command_size (enet_uint8 commandNumber)
+    {
+        return commandSizes [commandNumber & ENET_PROTOCOL_COMMAND_MASK];
+    }
+
+    static void
+    enet_protocol_change_state (ENetHost * host, ENetPeer * peer, ENetPeerState state)
+    {
+        if (state == ENET_PEER_STATE_CONNECTED || state == ENET_PEER_STATE_DISCONNECT_LATER)
+          enet_peer_on_connect (peer);
+        else
+          enet_peer_on_disconnect (peer);
+
+        peer -> state = state;
+    }
+
+    static void
+    enet_protocol_dispatch_state (ENetHost * host, ENetPeer * peer, ENetPeerState state)
+    {
+        enet_protocol_change_state (host, peer, state);
+
+        if (! peer -> needsDispatch)
+        {
+           enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList);
+
+           peer -> needsDispatch = 1;
+        }
+    }
+
+    static int
+    enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event)
+    {
+        while (! enet_list_empty (& host -> dispatchQueue))
+        {
+           ENetPeer * peer = (ENetPeer *) enet_list_remove (enet_list_begin (& host -> dispatchQueue));
+
+           peer -> needsDispatch = 0;
+
+           switch (peer -> state)
+           {
+           case ENET_PEER_STATE_CONNECTION_PENDING:
+           case ENET_PEER_STATE_CONNECTION_SUCCEEDED:
+               enet_protocol_change_state (host, peer, ENET_PEER_STATE_CONNECTED);
+
+               event -> type = ENET_EVENT_TYPE_CONNECT;
+               event -> peer = peer;
+               event -> data = peer -> eventData;
+
+               return 1;
+
+           case ENET_PEER_STATE_ZOMBIE:
+               host -> recalculateBandwidthLimits = 1;
+
+               event -> type = ENET_EVENT_TYPE_DISCONNECT;
+               event -> peer = peer;
+               event -> data = peer -> eventData;
+
+               enet_peer_reset (peer);
+
+               return 1;
+
+           case ENET_PEER_STATE_CONNECTED:
+               if (enet_list_empty (& peer -> dispatchedCommands))
+                 continue;
+
+               event -> packet = enet_peer_receive (peer, & event -> channelID);
+               if (event -> packet == NULL)
+                 continue;
+
+               event -> type = ENET_EVENT_TYPE_RECEIVE;
+               event -> peer = peer;
+
+               if (! enet_list_empty (& peer -> dispatchedCommands))
+               {
+                  peer -> needsDispatch = 1;
+
+                  enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList);
+               }
+
+               return 1;
+
+           default:
+               break;
+           }
+        }
+
+        return 0;
+    }
+
+    static void
+    enet_protocol_notify_connect (ENetHost * host, ENetPeer * peer, ENetEvent * event)
+    {
+        host -> recalculateBandwidthLimits = 1;
+
+        if (event != NULL)
+        {
+            enet_protocol_change_state (host, peer, ENET_PEER_STATE_CONNECTED);
+
+            event -> type = ENET_EVENT_TYPE_CONNECT;
+            event -> peer = peer;
+            event -> data = peer -> eventData;
+        }
+        else
+            enet_protocol_dispatch_state (host, peer, peer -> state == ENET_PEER_STATE_CONNECTING ? ENET_PEER_STATE_CONNECTION_SUCCEEDED : ENET_PEER_STATE_CONNECTION_PENDING);
+    }
+
+    static void
+    enet_protocol_notify_disconnect (ENetHost * host, ENetPeer * peer, ENetEvent * event)
+    {
+        if (peer -> state >= ENET_PEER_STATE_CONNECTION_PENDING)
+           host -> recalculateBandwidthLimits = 1;
+
+        if (peer -> state != ENET_PEER_STATE_CONNECTING && peer -> state < ENET_PEER_STATE_CONNECTION_SUCCEEDED)
+            enet_peer_reset (peer);
+        else
+        if (event != NULL)
+        {
+            event -> type = ENET_EVENT_TYPE_DISCONNECT;
+            event -> peer = peer;
+            event -> data = 0;
+
+            enet_peer_reset (peer);
+        }
+        else
+        {
+            peer -> eventData = 0;
+
+            enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE);
+        }
+    }
+
+    static void
+    enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer)
+    {
+        ENetOutgoingCommand * outgoingCommand;
+
+        while (! enet_list_empty (& peer -> sentUnreliableCommands))
+        {
+            outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentUnreliableCommands);
+
+            enet_list_remove (& outgoingCommand -> outgoingCommandList);
+
+            if (outgoingCommand -> packet != NULL)
+            {
+               -- outgoingCommand -> packet -> referenceCount;
+
+               if (outgoingCommand -> packet -> referenceCount == 0)
+               {
+                  outgoingCommand -> packet -> flags |= ENET_PACKET_FLAG_SENT;
+
+                  enet_packet_destroy (outgoingCommand -> packet);
+               }
+            }
+
+            enet_free (outgoingCommand);
+        }
+    }
+
+    static ENetProtocolCommand
+    enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID)
+    {
+        ENetOutgoingCommand * outgoingCommand = NULL;
+        ENetListIterator currentCommand;
+        ENetProtocolCommand commandNumber;
+        int wasSent = 1;
+
+        for (currentCommand = enet_list_begin (& peer -> sentReliableCommands);
+             currentCommand != enet_list_end (& peer -> sentReliableCommands);
+             currentCommand = enet_list_next (currentCommand))
+        {
+           outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+
+           if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber &&
+               outgoingCommand -> command.header.channelID == channelID)
+             break;
+        }
+
+        if (currentCommand == enet_list_end (& peer -> sentReliableCommands))
+        {
+           for (currentCommand = enet_list_begin (& peer -> outgoingReliableCommands);
+                currentCommand != enet_list_end (& peer -> outgoingReliableCommands);
+                currentCommand = enet_list_next (currentCommand))
+           {
+              outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+
+              if (outgoingCommand -> sendAttempts < 1) return ENET_PROTOCOL_COMMAND_NONE;
+
+              if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber &&
+                  outgoingCommand -> command.header.channelID == channelID)
+                break;
+           }
+
+           if (currentCommand == enet_list_end (& peer -> outgoingReliableCommands))
+             return ENET_PROTOCOL_COMMAND_NONE;
+
+           wasSent = 0;
+        }
+
+        if (outgoingCommand == NULL)
+          return ENET_PROTOCOL_COMMAND_NONE;
+
+        if (channelID < peer -> channelCount)
+        {
+           ENetChannel * channel = & peer -> channels [channelID];
+           enet_uint16 reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+           if (channel -> reliableWindows [reliableWindow] > 0)
+           {
+              -- channel -> reliableWindows [reliableWindow];
+              if (! channel -> reliableWindows [reliableWindow])
+                channel -> usedReliableWindows &= ~ (1 << reliableWindow);
+           }
+        }
+
+        commandNumber = (ENetProtocolCommand) (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK);
+
+        enet_list_remove (& outgoingCommand -> outgoingCommandList);
+
+        if (outgoingCommand -> packet != NULL)
+        {
+           if (wasSent)
+             peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength;
+
+           -- outgoingCommand -> packet -> referenceCount;
+
+           if (outgoingCommand -> packet -> referenceCount == 0)
+           {
+              outgoingCommand -> packet -> flags |= ENET_PACKET_FLAG_SENT;
+
+              enet_packet_destroy (outgoingCommand -> packet);
+           }
+        }
+
+        enet_free (outgoingCommand);
+
+        if (enet_list_empty (& peer -> sentReliableCommands))
+          return commandNumber;
+
+        outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentReliableCommands);
+
+        peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout;
+
+        return commandNumber;
+    }
+
+    static ENetPeer *
+    enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENetProtocol * command)
+    {
+        enet_uint8 incomingSessionID, outgoingSessionID;
+        enet_uint32 mtu, windowSize;
+        ENetChannel * channel;
+        size_t channelCount, duplicatePeers = 0;
+        ENetPeer * currentPeer, * peer = NULL;
+        ENetProtocol verifyCommand;
+
+        channelCount = ENET_NET_TO_HOST_32 (command -> connect.channelCount);
+
+        if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT ||
+            channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
+          return NULL;
+
+        for (currentPeer = host -> peers;
+             currentPeer < & host -> peers [host -> peerCount];
+             ++ currentPeer)
+        {
+            if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED)
+            {
+                if (peer == NULL)
+                  peer = currentPeer;
+            }
+            else
+            if (currentPeer -> state != ENET_PEER_STATE_CONNECTING &&
+                currentPeer -> address.host == host -> receivedAddress.host)
+            {
+                if (currentPeer -> address.port == host -> receivedAddress.port &&
+                    currentPeer -> connectID == command -> connect.connectID)
+                  return NULL;
+
+                ++ duplicatePeers;
+            }
+        }
+
+        if (peer == NULL || duplicatePeers >= host -> duplicatePeers)
+          return NULL;
+
+        if (channelCount > host -> channelLimit)
+          channelCount = host -> channelLimit;
+        peer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel));
+        if (peer -> channels == NULL)
+          return NULL;
+        peer -> channelCount = channelCount;
+        peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT;
+        peer -> connectID = command -> connect.connectID;
+        peer -> address = host -> receivedAddress;
+        peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> connect.outgoingPeerID);
+        peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.incomingBandwidth);
+        peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.outgoingBandwidth);
+        peer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleInterval);
+        peer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleAcceleration);
+        peer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleDeceleration);
+        peer -> eventData = ENET_NET_TO_HOST_32 (command -> connect.data);
+
+        incomingSessionID = command -> connect.incomingSessionID == 0xFF ? peer -> outgoingSessionID : command -> connect.incomingSessionID;
+        incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT);
+        if (incomingSessionID == peer -> outgoingSessionID)
+          incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT);
+        peer -> outgoingSessionID = incomingSessionID;
+
+        outgoingSessionID = command -> connect.outgoingSessionID == 0xFF ? peer -> incomingSessionID : command -> connect.outgoingSessionID;
+        outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT);
+        if (outgoingSessionID == peer -> incomingSessionID)
+          outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT);
+        peer -> incomingSessionID = outgoingSessionID;
+
+        for (channel = peer -> channels;
+             channel < & peer -> channels [channelCount];
+             ++ channel)
+        {
+            channel -> outgoingReliableSequenceNumber = 0;
+            channel -> outgoingUnreliableSequenceNumber = 0;
+            channel -> incomingReliableSequenceNumber = 0;
+            channel -> incomingUnreliableSequenceNumber = 0;
+
+            enet_list_clear (& channel -> incomingReliableCommands);
+            enet_list_clear (& channel -> incomingUnreliableCommands);
+
+            channel -> usedReliableWindows = 0;
+            memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows));
+        }
+
+        mtu = ENET_NET_TO_HOST_32 (command -> connect.mtu);
+
+        if (mtu < ENET_PROTOCOL_MINIMUM_MTU)
+          mtu = ENET_PROTOCOL_MINIMUM_MTU;
+        else
+        if (mtu > ENET_PROTOCOL_MAXIMUM_MTU)
+          mtu = ENET_PROTOCOL_MAXIMUM_MTU;
+
+        peer -> mtu = mtu;
+
+        if (host -> outgoingBandwidth == 0 &&
+            peer -> incomingBandwidth == 0)
+          peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+        else
+        if (host -> outgoingBandwidth == 0 ||
+            peer -> incomingBandwidth == 0)
+          peer -> windowSize = (ENET_MAX (host -> outgoingBandwidth, peer -> incomingBandwidth) /
+                                        ENET_PEER_WINDOW_SIZE_SCALE) *
+                                          ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+        else
+          peer -> windowSize = (ENET_MIN (host -> outgoingBandwidth, peer -> incomingBandwidth) /
+                                        ENET_PEER_WINDOW_SIZE_SCALE) *
+                                          ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+
+        if (peer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
+          peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+        else
+        if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
+          peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+
+        if (host -> incomingBandwidth == 0)
+          windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+        else
+          windowSize = (host -> incomingBandwidth / ENET_PEER_WINDOW_SIZE_SCALE) *
+                         ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+
+        if (windowSize > ENET_NET_TO_HOST_32 (command -> connect.windowSize))
+          windowSize = ENET_NET_TO_HOST_32 (command -> connect.windowSize);
+
+        if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
+          windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+        else
+        if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
+          windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+
+        verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+        verifyCommand.header.channelID = 0xFF;
+        verifyCommand.verifyConnect.outgoingPeerID = ENET_HOST_TO_NET_16 (peer -> incomingPeerID);
+        verifyCommand.verifyConnect.incomingSessionID = incomingSessionID;
+        verifyCommand.verifyConnect.outgoingSessionID = outgoingSessionID;
+        verifyCommand.verifyConnect.mtu = ENET_HOST_TO_NET_32 (peer -> mtu);
+        verifyCommand.verifyConnect.windowSize = ENET_HOST_TO_NET_32 (windowSize);
+        verifyCommand.verifyConnect.channelCount = ENET_HOST_TO_NET_32 (channelCount);
+        verifyCommand.verifyConnect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth);
+        verifyCommand.verifyConnect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
+        verifyCommand.verifyConnect.packetThrottleInterval = ENET_HOST_TO_NET_32 (peer -> packetThrottleInterval);
+        verifyCommand.verifyConnect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (peer -> packetThrottleAcceleration);
+        verifyCommand.verifyConnect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (peer -> packetThrottleDeceleration);
+        verifyCommand.verifyConnect.connectID = peer -> connectID;
+
+        enet_peer_queue_outgoing_command (peer, & verifyCommand, NULL, 0, 0);
+
+        return peer;
+    }
+
+    static int
+    enet_protocol_handle_send_reliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData)
+    {
+        size_t dataLength;
+
+        if (command -> header.channelID >= peer -> channelCount ||
+            (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER))
+          return -1;
+
+        dataLength = ENET_NET_TO_HOST_16 (command -> sendReliable.dataLength);
+        * currentData += dataLength;
+        if (dataLength > host -> maximumPacketSize ||
+            * currentData < host -> receivedData ||
+            * currentData > & host -> receivedData [host -> receivedDataLength])
+          return -1;
+
+        if (enet_peer_queue_incoming_command (peer, command, (const enet_uint8 *) command + sizeof (ENetProtocolSendReliable), dataLength, ENET_PACKET_FLAG_RELIABLE, 0) == NULL)
+          return -1;
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_send_unsequenced (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData)
+    {
+        enet_uint32 unsequencedGroup, index;
+        size_t dataLength;
+
+        if (command -> header.channelID >= peer -> channelCount ||
+            (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER))
+          return -1;
+
+        dataLength = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.dataLength);
+        * currentData += dataLength;
+        if (dataLength > host -> maximumPacketSize ||
+            * currentData < host -> receivedData ||
+            * currentData > & host -> receivedData [host -> receivedDataLength])
+          return -1;
+
+        unsequencedGroup = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.unsequencedGroup);
+        index = unsequencedGroup % ENET_PEER_UNSEQUENCED_WINDOW_SIZE;
+
+        if (unsequencedGroup < peer -> incomingUnsequencedGroup)
+          unsequencedGroup += 0x10000;
+
+        if (unsequencedGroup >= (enet_uint32) peer -> incomingUnsequencedGroup + ENET_PEER_FREE_UNSEQUENCED_WINDOWS * ENET_PEER_UNSEQUENCED_WINDOW_SIZE)
+          return 0;
+
+        unsequencedGroup &= 0xFFFF;
+
+        if (unsequencedGroup - index != peer -> incomingUnsequencedGroup)
+        {
+            peer -> incomingUnsequencedGroup = unsequencedGroup - index;
+
+            memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow));
+        }
+        else
+        if (peer -> unsequencedWindow [index / 32] & (1 << (index % 32)))
+          return 0;
+
+        if (enet_peer_queue_incoming_command (peer, command, (const enet_uint8 *) command + sizeof (ENetProtocolSendUnsequenced), dataLength, ENET_PACKET_FLAG_UNSEQUENCED, 0) == NULL)
+          return -1;
+
+        peer -> unsequencedWindow [index / 32] |= 1 << (index % 32);
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_send_unreliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData)
+    {
+        size_t dataLength;
+
+        if (command -> header.channelID >= peer -> channelCount ||
+            (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER))
+          return -1;
+
+        dataLength = ENET_NET_TO_HOST_16 (command -> sendUnreliable.dataLength);
+        * currentData += dataLength;
+        if (dataLength > host -> maximumPacketSize ||
+            * currentData < host -> receivedData ||
+            * currentData > & host -> receivedData [host -> receivedDataLength])
+          return -1;
+
+        if (enet_peer_queue_incoming_command (peer, command, (const enet_uint8 *) command + sizeof (ENetProtocolSendUnreliable), dataLength, 0, 0) == NULL)
+          return -1;
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData)
+    {
+        enet_uint32 fragmentNumber,
+               fragmentCount,
+               fragmentOffset,
+               fragmentLength,
+               startSequenceNumber,
+               totalLength;
+        ENetChannel * channel;
+        enet_uint16 startWindow, currentWindow;
+        ENetListIterator currentCommand;
+        ENetIncomingCommand * startCommand = NULL;
+
+        if (command -> header.channelID >= peer -> channelCount ||
+            (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER))
+          return -1;
+
+        fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength);
+        * currentData += fragmentLength;
+        if (fragmentLength > host -> maximumPacketSize ||
+            * currentData < host -> receivedData ||
+            * currentData > & host -> receivedData [host -> receivedDataLength])
+          return -1;
+
+        channel = & peer -> channels [command -> header.channelID];
+        startSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendFragment.startSequenceNumber);
+        startWindow = startSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+        currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+
+        if (startSequenceNumber < channel -> incomingReliableSequenceNumber)
+          startWindow += ENET_PEER_RELIABLE_WINDOWS;
+
+        if (startWindow < currentWindow || startWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1)
+          return 0;
+
+        fragmentNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentNumber);
+        fragmentCount = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentCount);
+        fragmentOffset = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentOffset);
+        totalLength = ENET_NET_TO_HOST_32 (command -> sendFragment.totalLength);
+
+        if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
+            fragmentNumber >= fragmentCount ||
+            totalLength > host -> maximumPacketSize ||
+            fragmentOffset >= totalLength ||
+            fragmentLength > totalLength - fragmentOffset)
+          return -1;
+
+        for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands));
+             currentCommand != enet_list_end (& channel -> incomingReliableCommands);
+             currentCommand = enet_list_previous (currentCommand))
+        {
+           ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
+
+           if (startSequenceNumber >= channel -> incomingReliableSequenceNumber)
+           {
+              if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+                continue;
+           }
+           else
+           if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
+             break;
+
+           if (incomingCommand -> reliableSequenceNumber <= startSequenceNumber)
+           {
+              if (incomingCommand -> reliableSequenceNumber < startSequenceNumber)
+                break;
+
+              if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_FRAGMENT ||
+                  totalLength != incomingCommand -> packet -> dataLength ||
+                  fragmentCount != incomingCommand -> fragmentCount)
+                return -1;
+
+              startCommand = incomingCommand;
+              break;
+           }
+        }
+
+        if (startCommand == NULL)
+        {
+           ENetProtocol hostCommand = * command;
+
+           hostCommand.header.reliableSequenceNumber = startSequenceNumber;
+
+           startCommand = enet_peer_queue_incoming_command (peer, & hostCommand, NULL, totalLength, ENET_PACKET_FLAG_RELIABLE, fragmentCount);
+           if (startCommand == NULL)
+             return -1;
+        }
+
+        if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0)
+        {
+           -- startCommand -> fragmentsRemaining;
+
+           startCommand -> fragments [fragmentNumber / 32] |= (1 << (fragmentNumber % 32));
+
+           if (fragmentOffset + fragmentLength > startCommand -> packet -> dataLength)
+             fragmentLength = startCommand -> packet -> dataLength - fragmentOffset;
+
+           memcpy (startCommand -> packet -> data + fragmentOffset,
+                   (enet_uint8 *) command + sizeof (ENetProtocolSendFragment),
+                   fragmentLength);
+
+            if (startCommand -> fragmentsRemaining <= 0)
+              enet_peer_dispatch_incoming_reliable_commands (peer, channel);
+        }
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_send_unreliable_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData)
+    {
+        enet_uint32 fragmentNumber,
+               fragmentCount,
+               fragmentOffset,
+               fragmentLength,
+               reliableSequenceNumber,
+               startSequenceNumber,
+               totalLength;
+        enet_uint16 reliableWindow, currentWindow;
+        ENetChannel * channel;
+        ENetListIterator currentCommand;
+        ENetIncomingCommand * startCommand = NULL;
+
+        if (command -> header.channelID >= peer -> channelCount ||
+            (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER))
+          return -1;
+
+        fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength);
+        * currentData += fragmentLength;
+        if (fragmentLength > host -> maximumPacketSize ||
+            * currentData < host -> receivedData ||
+            * currentData > & host -> receivedData [host -> receivedDataLength])
+          return -1;
+
+        channel = & peer -> channels [command -> header.channelID];
+        reliableSequenceNumber = command -> header.reliableSequenceNumber;
+        startSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendFragment.startSequenceNumber);
+
+        reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+        currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+
+        if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+          reliableWindow += ENET_PEER_RELIABLE_WINDOWS;
+
+        if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1)
+          return 0;
+
+        if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber &&
+            startSequenceNumber <= channel -> incomingUnreliableSequenceNumber)
+          return 0;
+
+        fragmentNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentNumber);
+        fragmentCount = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentCount);
+        fragmentOffset = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentOffset);
+        totalLength = ENET_NET_TO_HOST_32 (command -> sendFragment.totalLength);
+
+        if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
+            fragmentNumber >= fragmentCount ||
+            totalLength > host -> maximumPacketSize ||
+            fragmentOffset >= totalLength ||
+            fragmentLength > totalLength - fragmentOffset)
+          return -1;
+
+        for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands));
+             currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
+             currentCommand = enet_list_previous (currentCommand))
+        {
+           ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
+
+           if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
+           {
+              if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+                continue;
+           }
+           else
+           if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
+             break;
+
+           if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber)
+             break;
+
+           if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber)
+             continue;
+
+           if (incomingCommand -> unreliableSequenceNumber <= startSequenceNumber)
+           {
+              if (incomingCommand -> unreliableSequenceNumber < startSequenceNumber)
+                break;
+
+              if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT ||
+                  totalLength != incomingCommand -> packet -> dataLength ||
+                  fragmentCount != incomingCommand -> fragmentCount)
+                return -1;
+
+              startCommand = incomingCommand;
+              break;
+           }
+        }
+
+        if (startCommand == NULL)
+        {
+           startCommand = enet_peer_queue_incoming_command (peer, command, NULL, totalLength, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT, fragmentCount);
+           if (startCommand == NULL)
+             return -1;
+        }
+
+        if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0)
+        {
+           -- startCommand -> fragmentsRemaining;
+
+           startCommand -> fragments [fragmentNumber / 32] |= (1 << (fragmentNumber % 32));
+
+           if (fragmentOffset + fragmentLength > startCommand -> packet -> dataLength)
+             fragmentLength = startCommand -> packet -> dataLength - fragmentOffset;
+
+           memcpy (startCommand -> packet -> data + fragmentOffset,
+                   (enet_uint8 *) command + sizeof (ENetProtocolSendFragment),
+                   fragmentLength);
+
+            if (startCommand -> fragmentsRemaining <= 0)
+              enet_peer_dispatch_incoming_unreliable_commands (peer, channel);
+        }
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_ping (ENetHost * host, ENetPeer * peer, const ENetProtocol * command)
+    {
+        if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
+          return -1;
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_bandwidth_limit (ENetHost * host, ENetPeer * peer, const ENetProtocol * command)
+    {
+        if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
+          return -1;
+
+        if (peer -> incomingBandwidth != 0)
+          -- host -> bandwidthLimitedPeers;
+
+        peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.incomingBandwidth);
+        peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.outgoingBandwidth);
+
+        if (peer -> incomingBandwidth != 0)
+          ++ host -> bandwidthLimitedPeers;
+
+        if (peer -> incomingBandwidth == 0 && host -> outgoingBandwidth == 0)
+          peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+        else
+        if (peer -> incomingBandwidth == 0 || host -> outgoingBandwidth == 0)
+          peer -> windowSize = (ENET_MAX (peer -> incomingBandwidth, host -> outgoingBandwidth) /
+                                 ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+        else
+          peer -> windowSize = (ENET_MIN (peer -> incomingBandwidth, host -> outgoingBandwidth) /
+                                 ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+
+        if (peer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
+          peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+        else
+        if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
+          peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_throttle_configure (ENetHost * host, ENetPeer * peer, const ENetProtocol * command)
+    {
+        if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
+          return -1;
+
+        peer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleInterval);
+        peer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleAcceleration);
+        peer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleDeceleration);
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_disconnect (ENetHost * host, ENetPeer * peer, const ENetProtocol * command)
+    {
+        if (peer -> state == ENET_PEER_STATE_DISCONNECTED || peer -> state == ENET_PEER_STATE_ZOMBIE || peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT)
+          return 0;
+
+        enet_peer_reset_queues (peer);
+
+        if (peer -> state == ENET_PEER_STATE_CONNECTION_SUCCEEDED || peer -> state == ENET_PEER_STATE_DISCONNECTING || peer -> state == ENET_PEER_STATE_CONNECTING)
+            enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE);
+        else
+        if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
+        {
+            if (peer -> state == ENET_PEER_STATE_CONNECTION_PENDING) host -> recalculateBandwidthLimits = 1;
+
+            enet_peer_reset (peer);
+        }
+        else
+        if (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
+          enet_protocol_change_state (host, peer, ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT);
+        else
+          enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE);
+
+        if (peer -> state != ENET_PEER_STATE_DISCONNECTED)
+          peer -> eventData = ENET_NET_TO_HOST_32 (command -> disconnect.data);
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command)
+    {
+        enet_uint32 roundTripTime,
+               receivedSentTime,
+               receivedReliableSequenceNumber;
+        ENetProtocolCommand commandNumber;
+
+        if (peer -> state == ENET_PEER_STATE_DISCONNECTED || peer -> state == ENET_PEER_STATE_ZOMBIE)
+          return 0;
+
+        receivedSentTime = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedSentTime);
+        receivedSentTime |= host -> serviceTime & 0xFFFF0000;
+        if ((receivedSentTime & 0x8000) > (host -> serviceTime & 0x8000))
+            receivedSentTime -= 0x10000;
+
+        if (ENET_TIME_LESS (host -> serviceTime, receivedSentTime))
+          return 0;
+
+        peer -> lastReceiveTime = host -> serviceTime;
+        peer -> earliestTimeout = 0;
+
+        roundTripTime = ENET_TIME_DIFFERENCE (host -> serviceTime, receivedSentTime);
+
+        enet_peer_throttle (peer, roundTripTime);
+
+        peer -> roundTripTimeVariance -= peer -> roundTripTimeVariance / 4;
+
+        if (roundTripTime >= peer -> roundTripTime)
+        {
+           peer -> roundTripTime += (roundTripTime - peer -> roundTripTime) / 8;
+           peer -> roundTripTimeVariance += (roundTripTime - peer -> roundTripTime) / 4;
+        }
+        else
+        {
+           peer -> roundTripTime -= (peer -> roundTripTime - roundTripTime) / 8;
+           peer -> roundTripTimeVariance += (peer -> roundTripTime - roundTripTime) / 4;
+        }
+
+        if (peer -> roundTripTime < peer -> lowestRoundTripTime)
+          peer -> lowestRoundTripTime = peer -> roundTripTime;
+
+        if (peer -> roundTripTimeVariance > peer -> highestRoundTripTimeVariance)
+          peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance;
+
+        if (peer -> packetThrottleEpoch == 0 ||
+            ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> packetThrottleEpoch) >= peer -> packetThrottleInterval)
+        {
+            peer -> lastRoundTripTime = peer -> lowestRoundTripTime;
+            peer -> lastRoundTripTimeVariance = peer -> highestRoundTripTimeVariance;
+            peer -> lowestRoundTripTime = peer -> roundTripTime;
+            peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance;
+            peer -> packetThrottleEpoch = host -> serviceTime;
+        }
+
+        receivedReliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedReliableSequenceNumber);
+
+        commandNumber = enet_protocol_remove_sent_reliable_command (peer, receivedReliableSequenceNumber, command -> header.channelID);
+
+        switch (peer -> state)
+        {
+        case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT:
+           if (commandNumber != ENET_PROTOCOL_COMMAND_VERIFY_CONNECT)
+             return -1;
+
+           enet_protocol_notify_connect (host, peer, event);
+           break;
+
+        case ENET_PEER_STATE_DISCONNECTING:
+           if (commandNumber != ENET_PROTOCOL_COMMAND_DISCONNECT)
+             return -1;
+
+           enet_protocol_notify_disconnect (host, peer, event);
+           break;
+
+        case ENET_PEER_STATE_DISCONNECT_LATER:
+           if (enet_list_empty (& peer -> outgoingReliableCommands) &&
+               enet_list_empty (& peer -> outgoingUnreliableCommands) &&
+               enet_list_empty (& peer -> sentReliableCommands))
+             enet_peer_disconnect (peer, peer -> eventData);
+           break;
+
+        default:
+           break;
+        }
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_verify_connect (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command)
+    {
+        enet_uint32 mtu, windowSize;
+        size_t channelCount;
+
+        if (peer -> state != ENET_PEER_STATE_CONNECTING)
+          return 0;
+
+        channelCount = ENET_NET_TO_HOST_32 (command -> verifyConnect.channelCount);
+
+        if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT ||
+            ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleInterval) != peer -> packetThrottleInterval ||
+            ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleAcceleration) != peer -> packetThrottleAcceleration ||
+            ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleDeceleration) != peer -> packetThrottleDeceleration ||
+            command -> verifyConnect.connectID != peer -> connectID)
+        {
+            peer -> eventData = 0;
+
+            enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE);
+
+            return -1;
+        }
+
+        enet_protocol_remove_sent_reliable_command (peer, 1, 0xFF);
+
+        if (channelCount < peer -> channelCount)
+          peer -> channelCount = channelCount;
+
+        peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> verifyConnect.outgoingPeerID);
+        peer -> incomingSessionID = command -> verifyConnect.incomingSessionID;
+        peer -> outgoingSessionID = command -> verifyConnect.outgoingSessionID;
+
+        mtu = ENET_NET_TO_HOST_32 (command -> verifyConnect.mtu);
+
+        if (mtu < ENET_PROTOCOL_MINIMUM_MTU)
+          mtu = ENET_PROTOCOL_MINIMUM_MTU;
+        else
+        if (mtu > ENET_PROTOCOL_MAXIMUM_MTU)
+          mtu = ENET_PROTOCOL_MAXIMUM_MTU;
+
+        if (mtu < peer -> mtu)
+          peer -> mtu = mtu;
+
+        windowSize = ENET_NET_TO_HOST_32 (command -> verifyConnect.windowSize);
+
+        if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
+          windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+
+        if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
+          windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+
+        if (windowSize < peer -> windowSize)
+          peer -> windowSize = windowSize;
+
+        peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.incomingBandwidth);
+        peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.outgoingBandwidth);
+
+        enet_protocol_notify_connect (host, peer, event);
+        return 0;
+    }
+
+    static int
+    enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
+    {
+        ENetProtocolHeader * header;
+        ENetProtocol * command;
+        ENetPeer * peer;
+        enet_uint8 * currentData;
+        size_t headerSize;
+        enet_uint16 peerID, flags;
+        enet_uint8 sessionID;
+
+        if (host -> receivedDataLength < (size_t) & ((ENetProtocolHeader *) 0) -> sentTime)
+          return 0;
+
+        header = (ENetProtocolHeader *) host -> receivedData;
+
+        peerID = ENET_NET_TO_HOST_16 (header -> peerID);
+        sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT;
+        flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK;
+        peerID &= ~ (ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK);
+
+        headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof (ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *) 0) -> sentTime);
+        if (host -> checksum != NULL)
+          headerSize += sizeof (enet_uint32);
+
+        if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID)
+          peer = NULL;
+        else
+        if (peerID >= host -> peerCount)
+          return 0;
+        else
+        {
+           peer = & host -> peers [peerID];
+
+           if (peer -> state == ENET_PEER_STATE_DISCONNECTED ||
+               peer -> state == ENET_PEER_STATE_ZOMBIE ||
+               ((host -> receivedAddress.host != peer -> address.host ||
+                 host -> receivedAddress.port != peer -> address.port) &&
+                 peer -> address.host != ENET_HOST_BROADCAST) ||
+               (peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID &&
+                sessionID != peer -> incomingSessionID))
+             return 0;
+        }
+
+        if (flags & ENET_PROTOCOL_HEADER_FLAG_COMPRESSED)
+        {
+            size_t originalSize;
+            if (host -> compressor.context == NULL || host -> compressor.decompress == NULL)
+              return 0;
+
+            originalSize = host -> compressor.decompress (host -> compressor.context,
+                                        host -> receivedData + headerSize,
+                                        host -> receivedDataLength - headerSize,
+                                        host -> packetData [1] + headerSize,
+                                        sizeof (host -> packetData [1]) - headerSize);
+            if (originalSize <= 0 || originalSize > sizeof (host -> packetData [1]) - headerSize)
+              return 0;
+
+            memcpy (host -> packetData [1], header, headerSize);
+            host -> receivedData = host -> packetData [1];
+            host -> receivedDataLength = headerSize + originalSize;
+        }
+
+        if (host -> checksum != NULL)
+        {
+            enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)],
+                        desiredChecksum = * checksum;
+            ENetBuffer buffer;
+
+            * checksum = peer != NULL ? peer -> connectID : 0;
+
+            buffer.data = host -> receivedData;
+            buffer.dataLength = host -> receivedDataLength;
+
+            if (host -> checksum (& buffer, 1) != desiredChecksum)
+              return 0;
+        }
+
+        if (peer != NULL)
+        {
+           peer -> address.host = host -> receivedAddress.host;
+           peer -> address.port = host -> receivedAddress.port;
+           peer -> incomingDataTotal += host -> receivedDataLength;
+        }
+
+        currentData = host -> receivedData + headerSize;
+
+        while (currentData < & host -> receivedData [host -> receivedDataLength])
+        {
+           enet_uint8 commandNumber;
+           size_t commandSize;
+
+           command = (ENetProtocol *) currentData;
+
+           if (currentData + sizeof (ENetProtocolCommandHeader) > & host -> receivedData [host -> receivedDataLength])
+             break;
+
+           commandNumber = command -> header.command & ENET_PROTOCOL_COMMAND_MASK;
+           if (commandNumber >= ENET_PROTOCOL_COMMAND_COUNT)
+             break;
+
+           commandSize = commandSizes [commandNumber];
+           if (commandSize == 0 || currentData + commandSize > & host -> receivedData [host -> receivedDataLength])
+             break;
+
+           currentData += commandSize;
+
+           if (peer == NULL && commandNumber != ENET_PROTOCOL_COMMAND_CONNECT)
+             break;
+
+           command -> header.reliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> header.reliableSequenceNumber);
+
+           switch (commandNumber)
+           {
+           case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE:
+              if (enet_protocol_handle_acknowledge (host, event, peer, command))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_CONNECT:
+              if (peer != NULL)
+                goto commandError;
+              peer = enet_protocol_handle_connect (host, header, command);
+              if (peer == NULL)
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT:
+              if (enet_protocol_handle_verify_connect (host, event, peer, command))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_DISCONNECT:
+              if (enet_protocol_handle_disconnect (host, peer, command))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_PING:
+              if (enet_protocol_handle_ping (host, peer, command))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_SEND_RELIABLE:
+              if (enet_protocol_handle_send_reliable (host, peer, command, & currentData))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
+              if (enet_protocol_handle_send_unreliable (host, peer, command, & currentData))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
+              if (enet_protocol_handle_send_unsequenced (host, peer, command, & currentData))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:
+              if (enet_protocol_handle_send_fragment (host, peer, command, & currentData))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT:
+              if (enet_protocol_handle_bandwidth_limit (host, peer, command))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE:
+              if (enet_protocol_handle_throttle_configure (host, peer, command))
+                goto commandError;
+              break;
+
+           case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:
+              if (enet_protocol_handle_send_unreliable_fragment (host, peer, command, & currentData))
+                goto commandError;
+              break;
+
+           default:
+              goto commandError;
+           }
+
+           if (peer != NULL &&
+               (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0)
+           {
+               enet_uint16 sentTime;
+
+               if (! (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME))
+                 break;
+
+               sentTime = ENET_NET_TO_HOST_16 (header -> sentTime);
+
+               switch (peer -> state)
+               {
+               case ENET_PEER_STATE_DISCONNECTING:
+               case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT:
+               case ENET_PEER_STATE_DISCONNECTED:
+               case ENET_PEER_STATE_ZOMBIE:
+                  break;
+
+               case ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT:
+                  if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT)
+                    enet_peer_queue_acknowledgement (peer, command, sentTime);
+                  break;
+
+               default:
+                  enet_peer_queue_acknowledgement (peer, command, sentTime);
+                  break;
+               }
+           }
+        }
+
+    commandError:
+        if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE)
+          return 1;
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event)
+    {
+        int packets;
+
+        for (packets = 0; packets < 256; ++ packets)
+        {
+           int receivedLength;
+           ENetBuffer buffer;
+
+           buffer.data = host -> packetData [0];
+           buffer.dataLength = sizeof (host -> packetData [0]);
+
+           receivedLength = enet_socket_receive (host -> socket,
+                                                 & host -> receivedAddress,
+                                                 & buffer,
+                                                 1);
+
+           if (receivedLength < 0)
+             return -1;
+
+           if (receivedLength == 0)
+             return 0;
+
+           host -> receivedData = host -> packetData [0];
+           host -> receivedDataLength = receivedLength;
+
+           host -> totalReceivedData += receivedLength;
+           host -> totalReceivedPackets ++;
+
+           if (host -> intercept != NULL)
+           {
+              switch (host -> intercept (host, event))
+              {
+              case 1:
+                 if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE)
+                   return 1;
+
+                 continue;
+
+              case -1:
+                 return -1;
+
+              default:
+                 break;
+              }
+           }
+
+           switch (enet_protocol_handle_incoming_commands (host, event))
+           {
+           case 1:
+              return 1;
+
+           case -1:
+              return -1;
+
+           default:
+              break;
+           }
+        }
+
+        return -1;
+    }
+
+    static void
+    enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer)
+    {
+        ENetProtocol * command = & host -> commands [host -> commandCount];
+        ENetBuffer * buffer = & host -> buffers [host -> bufferCount];
+        ENetAcknowledgement * acknowledgement;
+        ENetListIterator currentAcknowledgement;
+        enet_uint16 reliableSequenceNumber;
+
+        currentAcknowledgement = enet_list_begin (& peer -> acknowledgements);
+
+        while (currentAcknowledgement != enet_list_end (& peer -> acknowledgements))
+        {
+           if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] ||
+               buffer >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] ||
+               peer -> mtu - host -> packetSize < sizeof (ENetProtocolAcknowledge))
+           {
+              host -> continueSending = 1;
+
+              break;
+           }
+
+           acknowledgement = (ENetAcknowledgement *) currentAcknowledgement;
+
+           currentAcknowledgement = enet_list_next (currentAcknowledgement);
+
+           buffer -> data = command;
+           buffer -> dataLength = sizeof (ENetProtocolAcknowledge);
+
+           host -> packetSize += buffer -> dataLength;
+
+           reliableSequenceNumber = ENET_HOST_TO_NET_16 (acknowledgement -> command.header.reliableSequenceNumber);
+
+           command -> header.command = ENET_PROTOCOL_COMMAND_ACKNOWLEDGE;
+           command -> header.channelID = acknowledgement -> command.header.channelID;
+           command -> header.reliableSequenceNumber = reliableSequenceNumber;
+           command -> acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber;
+           command -> acknowledge.receivedSentTime = ENET_HOST_TO_NET_16 (acknowledgement -> sentTime);
+
+           if ((acknowledgement -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT)
+             enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE);
+
+           enet_list_remove (& acknowledgement -> acknowledgementList);
+           enet_free (acknowledgement);
+
+           ++ command;
+           ++ buffer;
+        }
+
+        host -> commandCount = command - host -> commands;
+        host -> bufferCount = buffer - host -> buffers;
+    }
+
+    static void
+    enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * peer)
+    {
+        ENetProtocol * command = & host -> commands [host -> commandCount];
+        ENetBuffer * buffer = & host -> buffers [host -> bufferCount];
+        ENetOutgoingCommand * outgoingCommand;
+        ENetListIterator currentCommand;
+
+        currentCommand = enet_list_begin (& peer -> outgoingUnreliableCommands);
+
+        while (currentCommand != enet_list_end (& peer -> outgoingUnreliableCommands))
+        {
+           size_t commandSize;
+
+           outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+           commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK];
+
+           if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] ||
+               buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] ||
+               peer -> mtu - host -> packetSize < commandSize ||
+               (outgoingCommand -> packet != NULL &&
+                 peer -> mtu - host -> packetSize < commandSize + outgoingCommand -> fragmentLength))
+           {
+              host -> continueSending = 1;
+
+              break;
+           }
+
+           currentCommand = enet_list_next (currentCommand);
+
+           if (outgoingCommand -> packet != NULL && outgoingCommand -> fragmentOffset == 0)
+           {
+              peer -> packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER;
+              peer -> packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE;
+
+              if (peer -> packetThrottleCounter > peer -> packetThrottle)
+              {
+                 enet_uint16 reliableSequenceNumber = outgoingCommand -> reliableSequenceNumber,
+                             unreliableSequenceNumber = outgoingCommand -> unreliableSequenceNumber;
+                 for (;;)
+                 {
+                    -- outgoingCommand -> packet -> referenceCount;
+
+                    if (outgoingCommand -> packet -> referenceCount == 0)
+                      enet_packet_destroy (outgoingCommand -> packet);
+
+                    enet_list_remove (& outgoingCommand -> outgoingCommandList);
+                    enet_free (outgoingCommand);
+
+                    if (currentCommand == enet_list_end (& peer -> outgoingUnreliableCommands))
+                      break;
+
+                    outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+                    if (outgoingCommand -> reliableSequenceNumber != reliableSequenceNumber ||
+                        outgoingCommand -> unreliableSequenceNumber != unreliableSequenceNumber)
+                      break;
+
+                    currentCommand = enet_list_next (currentCommand);
+                 }
+
+                 continue;
+              }
+           }
+
+           buffer -> data = command;
+           buffer -> dataLength = commandSize;
+
+           host -> packetSize += buffer -> dataLength;
+
+           * command = outgoingCommand -> command;
+
+           enet_list_remove (& outgoingCommand -> outgoingCommandList);
+
+           if (outgoingCommand -> packet != NULL)
+           {
+              ++ buffer;
+
+              buffer -> data = outgoingCommand -> packet -> data + outgoingCommand -> fragmentOffset;
+              buffer -> dataLength = outgoingCommand -> fragmentLength;
+
+              host -> packetSize += buffer -> dataLength;
+
+              enet_list_insert (enet_list_end (& peer -> sentUnreliableCommands), outgoingCommand);
+           }
+           else
+             enet_free (outgoingCommand);
+
+           ++ command;
+           ++ buffer;
+        }
+
+        host -> commandCount = command - host -> commands;
+        host -> bufferCount = buffer - host -> buffers;
+
+        if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER &&
+            enet_list_empty (& peer -> outgoingReliableCommands) &&
+            enet_list_empty (& peer -> outgoingUnreliableCommands) &&
+            enet_list_empty (& peer -> sentReliableCommands))
+          enet_peer_disconnect (peer, peer -> eventData);
+    }
+
+    static int
+    enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event)
+    {
+        ENetOutgoingCommand * outgoingCommand;
+        ENetListIterator currentCommand, insertPosition;
+
+        currentCommand = enet_list_begin (& peer -> sentReliableCommands);
+        insertPosition = enet_list_begin (& peer -> outgoingReliableCommands);
+
+        while (currentCommand != enet_list_end (& peer -> sentReliableCommands))
+        {
+           outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+
+           currentCommand = enet_list_next (currentCommand);
+
+           if (ENET_TIME_DIFFERENCE (host -> serviceTime, outgoingCommand -> sentTime) < outgoingCommand -> roundTripTimeout)
+             continue;
+
+           if (peer -> earliestTimeout == 0 ||
+               ENET_TIME_LESS (outgoingCommand -> sentTime, peer -> earliestTimeout))
+             peer -> earliestTimeout = outgoingCommand -> sentTime;
+
+           if (peer -> earliestTimeout != 0 &&
+                 (ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMaximum ||
+                   (outgoingCommand -> roundTripTimeout >= outgoingCommand -> roundTripTimeoutLimit &&
+                     ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMinimum)))
+           {
+              enet_protocol_notify_disconnect (host, peer, event);
+
+              return 1;
+           }
+
+           if (outgoingCommand -> packet != NULL)
+             peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength;
+
+           ++ peer -> packetsLost;
+
+           outgoingCommand -> roundTripTimeout *= 2;
+
+           enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList));
+
+           if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) &&
+               ! enet_list_empty (& peer -> sentReliableCommands))
+           {
+              outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+
+              peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout;
+           }
+        }
+
+        return 0;
+    }
+
+    static int
+    enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer)
+    {
+        ENetProtocol * command = & host -> commands [host -> commandCount];
+        ENetBuffer * buffer = & host -> buffers [host -> bufferCount];
+        ENetOutgoingCommand * outgoingCommand;
+        ENetListIterator currentCommand;
+        ENetChannel *channel;
+        enet_uint16 reliableWindow;
+        size_t commandSize;
+        int windowExceeded = 0, windowWrap = 0, canPing = 1;
+
+        currentCommand = enet_list_begin (& peer -> outgoingReliableCommands);
+
+        while (currentCommand != enet_list_end (& peer -> outgoingReliableCommands))
+        {
+           outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+
+           channel = outgoingCommand -> command.header.channelID < peer -> channelCount ? & peer -> channels [outgoingCommand -> command.header.channelID] : NULL;
+           reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+           if (channel != NULL)
+           {
+               if (! windowWrap &&
+                   outgoingCommand -> sendAttempts < 1 &&
+                   ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) &&
+                   (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE ||
+                     channel -> usedReliableWindows & ((((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) << reliableWindow) |
+                       (((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow)))))
+                 windowWrap = 1;
+              if (windowWrap)
+              {
+                 currentCommand = enet_list_next (currentCommand);
+
+                 continue;
+              }
+           }
+
+           if (outgoingCommand -> packet != NULL)
+           {
+              if (! windowExceeded)
+              {
+                 enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE;
+
+                 if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu))
+                   windowExceeded = 1;
+              }
+              if (windowExceeded)
+              {
+                 currentCommand = enet_list_next (currentCommand);
+
+                 continue;
+              }
+           }
+
+           canPing = 0;
+
+           commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK];
+           if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] ||
+               buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] ||
+               peer -> mtu - host -> packetSize < commandSize ||
+               (outgoingCommand -> packet != NULL &&
+                 (enet_uint16) (peer -> mtu - host -> packetSize) < (enet_uint16) (commandSize + outgoingCommand -> fragmentLength)))
+           {
+              host -> continueSending = 1;
+
+              break;
+           }
+
+           currentCommand = enet_list_next (currentCommand);
+
+           if (channel != NULL && outgoingCommand -> sendAttempts < 1)
+           {
+              channel -> usedReliableWindows |= 1 << reliableWindow;
+              ++ channel -> reliableWindows [reliableWindow];
+           }
+
+           ++ outgoingCommand -> sendAttempts;
+
+           if (outgoingCommand -> roundTripTimeout == 0)
+           {
+              outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance;
+              outgoingCommand -> roundTripTimeoutLimit = peer -> timeoutLimit * outgoingCommand -> roundTripTimeout;
+           }
+
+           if (enet_list_empty (& peer -> sentReliableCommands))
+             peer -> nextTimeout = host -> serviceTime + outgoingCommand -> roundTripTimeout;
+
+           enet_list_insert (enet_list_end (& peer -> sentReliableCommands),
+                             enet_list_remove (& outgoingCommand -> outgoingCommandList));
+
+           outgoingCommand -> sentTime = host -> serviceTime;
+
+           buffer -> data = command;
+           buffer -> dataLength = commandSize;
+
+           host -> packetSize += buffer -> dataLength;
+           host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME;
+
+           * command = outgoingCommand -> command;
+
+           if (outgoingCommand -> packet != NULL)
+           {
+              ++ buffer;
+
+              buffer -> data = outgoingCommand -> packet -> data + outgoingCommand -> fragmentOffset;
+              buffer -> dataLength = outgoingCommand -> fragmentLength;
+
+              host -> packetSize += outgoingCommand -> fragmentLength;
+
+              peer -> reliableDataInTransit += outgoingCommand -> fragmentLength;
+           }
+
+           ++ peer -> packetsSent;
+
+           ++ command;
+           ++ buffer;
+        }
+
+        host -> commandCount = command - host -> commands;
+        host -> bufferCount = buffer - host -> buffers;
+
+        return canPing;
+    }
+
+    static int
+    enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts)
+    {
+        enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)];
+        ENetProtocolHeader * header = (ENetProtocolHeader *) headerData;
+        ENetPeer * currentPeer;
+        int sentLength;
+        size_t shouldCompress = 0;
+
+        host -> continueSending = 1;
+
+        while (host -> continueSending)
+        for (host -> continueSending = 0,
+               currentPeer = host -> peers;
+             currentPeer < & host -> peers [host -> peerCount];
+             ++ currentPeer)
+        {
+            if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED ||
+                currentPeer -> state == ENET_PEER_STATE_ZOMBIE)
+              continue;
+
+            host -> headerFlags = 0;
+            host -> commandCount = 0;
+            host -> bufferCount = 1;
+            host -> packetSize = sizeof (ENetProtocolHeader);
+
+            if (! enet_list_empty (& currentPeer -> acknowledgements))
+              enet_protocol_send_acknowledgements (host, currentPeer);
+
+            if (checkForTimeouts != 0 &&
+                ! enet_list_empty (& currentPeer -> sentReliableCommands) &&
+                ENET_TIME_GREATER_EQUAL (host -> serviceTime, currentPeer -> nextTimeout) &&
+                enet_protocol_check_timeouts (host, currentPeer, event) == 1)
+            {
+                if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE)
+                  return 1;
+                else
+                  continue;
+            }
+
+            if ((enet_list_empty (& currentPeer -> outgoingReliableCommands) ||
+                  enet_protocol_send_reliable_outgoing_commands (host, currentPeer)) &&
+                enet_list_empty (& currentPeer -> sentReliableCommands) &&
+                ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= currentPeer -> pingInterval &&
+                currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing))
+            {
+                enet_peer_ping (currentPeer);
+                enet_protocol_send_reliable_outgoing_commands (host, currentPeer);
+            }
+
+            if (! enet_list_empty (& currentPeer -> outgoingUnreliableCommands))
+              enet_protocol_send_unreliable_outgoing_commands (host, currentPeer);
+
+            if (host -> commandCount == 0)
+              continue;
+
+            if (currentPeer -> packetLossEpoch == 0)
+              currentPeer -> packetLossEpoch = host -> serviceTime;
+            else
+            if (ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> packetLossEpoch) >= ENET_PEER_PACKET_LOSS_INTERVAL &&
+                currentPeer -> packetsSent > 0)
+            {
+               enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent;
+
+    #ifdef ENET_DEBUG
+               printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingReliableCommands), enet_list_size (& currentPeer -> outgoingUnreliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0);
+    #endif
+
+               currentPeer -> packetLossVariance -= currentPeer -> packetLossVariance / 4;
+
+               if (packetLoss >= currentPeer -> packetLoss)
+               {
+                  currentPeer -> packetLoss += (packetLoss - currentPeer -> packetLoss) / 8;
+                  currentPeer -> packetLossVariance += (packetLoss - currentPeer -> packetLoss) / 4;
+               }
+               else
+               {
+                  currentPeer -> packetLoss -= (currentPeer -> packetLoss - packetLoss) / 8;
+                  currentPeer -> packetLossVariance += (currentPeer -> packetLoss - packetLoss) / 4;
+               }
+
+               currentPeer -> packetLossEpoch = host -> serviceTime;
+               currentPeer -> packetsSent = 0;
+               currentPeer -> packetsLost = 0;
+            }
+
+            host -> buffers -> data = headerData;
+            if (host -> headerFlags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)
+            {
+                header -> sentTime = ENET_HOST_TO_NET_16 (host -> serviceTime & 0xFFFF);
+
+                host -> buffers -> dataLength = sizeof (ENetProtocolHeader);
+            }
+            else
+              host -> buffers -> dataLength = (size_t) & ((ENetProtocolHeader *) 0) -> sentTime;
+
+            shouldCompress = 0;
+            if (host -> compressor.context != NULL && host -> compressor.compress != NULL)
+            {
+                size_t originalSize = host -> packetSize - sizeof(ENetProtocolHeader),
+                       compressedSize = host -> compressor.compress (host -> compressor.context,
+                                            & host -> buffers [1], host -> bufferCount - 1,
+                                            originalSize,
+                                            host -> packetData [1],
+                                            originalSize);
+                if (compressedSize > 0 && compressedSize < originalSize)
+                {
+                    host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED;
+                    shouldCompress = compressedSize;
+    #ifdef ENET_DEBUG_COMPRESS
+                    printf ("peer %u: compressed %u -> %u (%u%%)\n", currentPeer -> incomingPeerID, originalSize, compressedSize, (compressedSize * 100) / originalSize);
+    #endif
+                }
+            }
+
+            if (currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID)
+              host -> headerFlags |= currentPeer -> outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT;
+            header -> peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID | host -> headerFlags);
+            if (host -> checksum != NULL)
+            {
+                enet_uint32 * checksum = (enet_uint32 *) & headerData [host -> buffers -> dataLength];
+                * checksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0;
+                host -> buffers -> dataLength += sizeof (enet_uint32);
+                * checksum = host -> checksum (host -> buffers, host -> bufferCount);
+            }
+
+            if (shouldCompress > 0)
+            {
+                host -> buffers [1].data = host -> packetData [1];
+                host -> buffers [1].dataLength = shouldCompress;
+                host -> bufferCount = 2;
+            }
+
+            currentPeer -> lastSendTime = host -> serviceTime;
+
+            sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount);
+
+            enet_protocol_remove_sent_unreliable_commands (currentPeer);
+
+            if (sentLength < 0)
+              return -1;
+
+            host -> totalSentData += sentLength;
+            host -> totalSentPackets ++;
+        }
+
+        return 0;
+    }
+
+    /** Sends any queued packets on the host specified to its designated peers.
+
+        @param host   host to flush
+        @remarks this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service().
+        @ingroup host
+    */
+    void
+    enet_host_flush (ENetHost * host)
+    {
+        host -> serviceTime = enet_time_get ();
+
+        enet_protocol_send_outgoing_commands (host, NULL, 0);
+    }
+
+    /** Checks for any queued events on the host and dispatches one if available.
+
+        @param host    host to check for events
+        @param event   an event structure where event details will be placed if available
+        @retval > 0 if an event was dispatched
+        @retval 0 if no events are available
+        @retval < 0 on failure
+        @ingroup host
+    */
+    int
+    enet_host_check_events (ENetHost * host, ENetEvent * event)
+    {
+        if (event == NULL) return -1;
+
+        event -> type = ENET_EVENT_TYPE_NONE;
+        event -> peer = NULL;
+        event -> packet = NULL;
+
+        return enet_protocol_dispatch_incoming_commands (host, event);
+    }
+
+    /** Waits for events on the host specified and shuttles packets between
+        the host and its peers.
+
+        @param host    host to service
+        @param event   an event structure where event details will be placed if one occurs
+                       if event == NULL then no events will be delivered
+        @param timeout number of milliseconds that ENet should wait for events
+        @retval > 0 if an event occurred within the specified time limit
+        @retval 0 if no event occurred
+        @retval < 0 on failure
+        @remarks enet_host_service should be called fairly regularly for adequate performance
+        @ingroup host
+    */
+    int
+    enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout)
+    {
+        enet_uint32 waitCondition;
+
+        if (event != NULL)
+        {
+            event -> type = ENET_EVENT_TYPE_NONE;
+            event -> peer = NULL;
+            event -> packet = NULL;
+
+            switch (enet_protocol_dispatch_incoming_commands (host, event))
+            {
+            case 1:
+                return 1;
+
+            case -1:
+    #ifdef ENET_DEBUG
+                perror ("Error dispatching incoming packets");
+    #endif
+
+                return -1;
+
+            default:
+                break;
+            }
+        }
+
+        host -> serviceTime = enet_time_get ();
+
+        timeout += host -> serviceTime;
+
+        do
+        {
+           if (ENET_TIME_DIFFERENCE (host -> serviceTime, host -> bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL)
+             enet_host_bandwidth_throttle (host);
+
+           switch (enet_protocol_send_outgoing_commands (host, event, 1))
+           {
+           case 1:
+              return 1;
+
+           case -1:
+    #ifdef ENET_DEBUG
+              perror ("Error sending outgoing packets");
+    #endif
+
+              return -1;
+
+           default:
+              break;
+           }
+
+           switch (enet_protocol_receive_incoming_commands (host, event))
+           {
+           case 1:
+              return 1;
+
+           case -1:
+    #ifdef ENET_DEBUG
+              perror ("Error receiving incoming packets");
+    #endif
+
+              return -1;
+
+           default:
+              break;
+           }
+
+           switch (enet_protocol_send_outgoing_commands (host, event, 1))
+           {
+           case 1:
+              return 1;
+
+           case -1:
+    #ifdef ENET_DEBUG
+              perror ("Error sending outgoing packets");
+    #endif
+
+              return -1;
+
+           default:
+              break;
+           }
+
+           if (event != NULL)
+           {
+              switch (enet_protocol_dispatch_incoming_commands (host, event))
+              {
+              case 1:
+                 return 1;
+
+              case -1:
+    #ifdef ENET_DEBUG
+                 perror ("Error dispatching incoming packets");
+    #endif
+
+                 return -1;
+
+              default:
+                 break;
+              }
+           }
+
+           if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout))
+             return 0;
+
+           do
+           {
+              host -> serviceTime = enet_time_get ();
+
+              if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout))
+                return 0;
+
+              waitCondition = ENET_SOCKET_WAIT_RECEIVE | ENET_SOCKET_WAIT_INTERRUPT;
+
+              if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0)
+                return -1;
+           }
+           while (waitCondition & ENET_SOCKET_WAIT_INTERRUPT);
+
+           host -> serviceTime = enet_time_get ();
+        } while (waitCondition & ENET_SOCKET_WAIT_RECEIVE);
+
+        return 0;
+    }
+
+    // @from_file: unix.c
+    /**
+     @file  unix.c
+     @brief ENet Unix system specific functions
+    */
+    #ifndef _WIN32
+
+
+
+    #include <sys/ioctl.h>
+
+    #include <arpa/inet.h>
+    #include <netinet/tcp.h>
+    #include <netdb.h>
+
+
+    #include <errno.h>
+    #include <time.h>
+
+    #define ENET_BUILDING_LIB 1
+
+
+    #ifdef __APPLE__
+    #ifdef HAS_POLL
+    #undef HAS_POLL
+    #endif
+    #ifndef HAS_FCNTL
+    #define HAS_FCNTL 1
+    #endif
+    #ifndef HAS_INET_PTON
+    #define HAS_INET_PTON 1
+    #endif
+    #ifndef HAS_INET_NTOP
+    #define HAS_INET_NTOP 1
+    #endif
+    #ifndef HAS_MSGHDR_FLAGS
+    #define HAS_MSGHDR_FLAGS 1
+    #endif
+    #ifndef HAS_SOCKLEN_T
+    #define HAS_SOCKLEN_T 1
+    #endif
+    #ifndef HAS_GETADDRINFO
+    #define HAS_GETADDRINFO 1
+    #endif
+    #ifndef HAS_GETNAMEINFO
+    #define HAS_GETNAMEINFO 1
+    #endif
+    #endif
+
+    #ifdef HAS_FCNTL
+    #include <fcntl.h>
+    #endif
+
+    #ifdef HAS_POLL
+    #include <sys/poll.h>
+    #endif
+
+    #ifndef HAS_SOCKLEN_T
+    typedef int socklen_t;
+    #endif
+
+    #ifndef MSG_NOSIGNAL
+    #define MSG_NOSIGNAL 0
+    #endif
+
+    static enet_uint64 timeBase = 0;
+
+    int
+    enet_initialize (void)
+    {
+        return 0;
+    }
+
+    void
+    enet_deinitialize (void)
+    {
+    }
+
+    enet_uint64
+    enet_host_random_seed (void)
+    {
+        return (enet_uint32) time (NULL);
+    }
+
+    enet_uint64
+    enet_time_get (void)
+    {
+        struct timeval timeVal;
+
+        gettimeofday (& timeVal, NULL);
+
+        return timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - timeBase;
+    }
+
+    void
+    enet_time_set (enet_uint64 newTimeBase)
+    {
+        struct timeval timeVal;
+
+        gettimeofday (& timeVal, NULL);
+
+        timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase;
+    }
+
+    int
+    enet_address_set_host_ip (ENetAddress * address, const char * name)
+    {
+    #ifdef HAS_INET_PTON
+        if (! inet_pton (AF_INET, name, & address -> host))
+    #else
+        if (! inet_aton (name, (struct in_addr *) & address -> host))
+    #endif
+            return -1;
+
+        return 0;
+    }
+
+    int
+    enet_address_set_host (ENetAddress * address, const char * name)
+    {
+    #ifdef HAS_GETADDRINFO
+        struct addrinfo hints, * resultList = NULL, * result = NULL;
+
+        memset (& hints, 0, sizeof (hints));
+        hints.ai_family = AF_INET;
+
+        if (getaddrinfo (name, NULL, NULL, & resultList) != 0)
+          return -1;
+
+        for (result = resultList; result != NULL; result = result -> ai_next)
+        {
+            if (result -> ai_family == AF_INET && result -> ai_addr != NULL && result -> ai_addrlen >= sizeof (struct sockaddr_in))
+            {
+                struct sockaddr_in * sin = (struct sockaddr_in *) result -> ai_addr;
+
+                address -> host = sin -> sin_addr.s_addr;
+
+                freeaddrinfo (resultList);
+
+                return 0;
+            }
+        }
+
+        if (resultList != NULL)
+          freeaddrinfo (resultList);
+    #else
+        struct hostent * hostEntry = NULL;
+    #ifdef HAS_GETHOSTBYNAME_R
+        struct hostent hostData;
+        char buffer [2048];
+        int errnum;
+
+    #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__)
+        gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum);
+    #else
+        hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum);
+    #endif
+    #else
+        hostEntry = gethostbyname (name);
+    #endif
+
+        if (hostEntry != NULL && hostEntry -> h_addrtype == AF_INET)
+        {
+            address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
+
+            return 0;
+        }
+    #endif
+
+        return enet_address_set_host_ip (address, name);
+    }
+
+    int
+    enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
+    {
+    #ifdef HAS_INET_NTOP
+        if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL)
+    #else
+        char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
+        if (addr != NULL)
+        {
+            size_t addrLen = strlen(addr);
+            if (addrLen >= nameLength)
+              return -1;
+            memcpy (name, addr, addrLen + 1);
+        }
+        else
+    #endif
+            return -1;
+        return 0;
+    }
+
+    int
+    enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
+    {
+    #ifdef HAS_GETNAMEINFO
+        struct sockaddr_in sin;
+        int err;
+
+        memset (& sin, 0, sizeof (struct sockaddr_in));
+
+        sin.sin_family = AF_INET;
+        sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+        sin.sin_addr.s_addr = address -> host;
+
+        err = getnameinfo ((struct sockaddr *) & sin, sizeof (sin), name, nameLength, NULL, 0, NI_NAMEREQD);
+        if (! err)
+        {
+            if (name != NULL && nameLength > 0 && ! memchr (name, '\0', nameLength))
+              return -1;
+            return 0;
+        }
+        if (err != EAI_NONAME)
+          return -1;
+    #else
+        struct in_addr in;
+        struct hostent * hostEntry = NULL;
+    #ifdef HAS_GETHOSTBYADDR_R
+        struct hostent hostData;
+        char buffer [2048];
+        int errnum;
+
+        in.s_addr = address -> host;
+
+    #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__)
+        gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum);
+    #else
+        hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum);
+    #endif
+    #else
+        in.s_addr = address -> host;
+
+        hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
+    #endif
+
+        if (hostEntry != NULL)
+        {
+           size_t hostLen = strlen (hostEntry -> h_name);
+           if (hostLen >= nameLength)
+             return -1;
+           memcpy (name, hostEntry -> h_name, hostLen + 1);
+           return 0;
+        }
+    #endif
+
+        return enet_address_get_host_ip (address, name, nameLength);
+    }
+
+    int
+    enet_socket_bind (ENetSocket socket, const ENetAddress * address)
+    {
+        struct sockaddr_in sin;
+
+        memset (& sin, 0, sizeof (struct sockaddr_in));
+
+        sin.sin_family = AF_INET;
+
+        if (address != NULL)
+        {
+           sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+           sin.sin_addr.s_addr = address -> host;
+        }
+        else
+        {
+           sin.sin_port = 0;
+           sin.sin_addr.s_addr = INADDR_ANY;
+        }
+
+        return bind (socket,
+                     (struct sockaddr *) & sin,
+                     sizeof (struct sockaddr_in));
+    }
+
+    int
+    enet_socket_get_address (ENetSocket socket, ENetAddress * address)
+    {
+        struct sockaddr_in sin;
+        socklen_t sinLength = sizeof (struct sockaddr_in);
+
+        if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
+          return -1;
+
+        address -> host = (enet_uint32) sin.sin_addr.s_addr;
+        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+
+        return 0;
+    }
+
+    int
+    enet_socket_listen (ENetSocket socket, int backlog)
+    {
+        return listen (socket, backlog < 0 ? SOMAXCONN : backlog);
+    }
+
+    ENetSocket
+    enet_socket_create (ENetSocketType type)
+    {
+        return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
+    }
+
+    int
+    enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
+    {
+        int result = -1;
+        switch (option)
+        {
+            case ENET_SOCKOPT_NONBLOCK:
+    #ifdef HAS_FCNTL
+                result = fcntl (socket, F_SETFL, (value ? O_NONBLOCK : 0) | (fcntl (socket, F_GETFL) & ~O_NONBLOCK));
+    #else
+                result = ioctl (socket, FIONBIO, & value);
+    #endif
+                break;
+
+            case ENET_SOCKOPT_BROADCAST:
+                result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_REUSEADDR:
+                result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_RCVBUF:
+                result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_SNDBUF:
+                result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_RCVTIMEO:
+            {
+                struct timeval timeVal;
+                timeVal.tv_sec = value / 1000;
+                timeVal.tv_usec = (value % 1000) * 1000;
+                result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & timeVal, sizeof (struct timeval));
+                break;
+            }
+
+            case ENET_SOCKOPT_SNDTIMEO:
+            {
+                struct timeval timeVal;
+                timeVal.tv_sec = value / 1000;
+                timeVal.tv_usec = (value % 1000) * 1000;
+                result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & timeVal, sizeof (struct timeval));
+                break;
+            }
+
+            case ENET_SOCKOPT_NODELAY:
+                result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int));
+                break;
+
+            default:
+                break;
+        }
+        return result == -1 ? -1 : 0;
+    }
+
+    int
+    enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value)
+    {
+        int result = -1;
+        socklen_t len;
+        switch (option)
+        {
+            case ENET_SOCKOPT_ERROR:
+                len = sizeof (int);
+                result = getsockopt (socket, SOL_SOCKET, SO_ERROR, value, & len);
+                break;
+
+            default:
+                break;
+        }
+        return result == -1 ? -1 : 0;
+    }
+
+    int
+    enet_socket_connect (ENetSocket socket, const ENetAddress * address)
+    {
+        struct sockaddr_in sin;
+        int result;
+
+        memset (& sin, 0, sizeof (struct sockaddr_in));
+
+        sin.sin_family = AF_INET;
+        sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+        sin.sin_addr.s_addr = address -> host;
+
+        result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
+        if (result == -1 && errno == EINPROGRESS)
+          return 0;
+
+        return result;
+    }
+
+    ENetSocket
+    enet_socket_accept (ENetSocket socket, ENetAddress * address)
+    {
+        int result;
+        struct sockaddr_in sin;
+        socklen_t sinLength = sizeof (struct sockaddr_in);
+
+        result = accept (socket,
+                         address != NULL ? (struct sockaddr *) & sin : NULL,
+                         address != NULL ? & sinLength : NULL);
+
+        if (result == -1)
+          return ENET_SOCKET_NULL;
+
+        if (address != NULL)
+        {
+            address -> host = (enet_uint32) sin.sin_addr.s_addr;
+            address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+        }
+
+        return result;
+    }
+
+    int
+    enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how)
+    {
+        return shutdown (socket, (int) how);
+    }
+
+    void
+    enet_socket_destroy (ENetSocket socket)
+    {
+        if (socket != -1)
+          close (socket);
+    }
+
+    int
+    enet_socket_send (ENetSocket socket,
+                      const ENetAddress * address,
+                      const ENetBuffer * buffers,
+                      size_t bufferCount)
+    {
+        struct msghdr msgHdr;
+        struct sockaddr_in sin;
+        int sentLength;
+
+        memset (& msgHdr, 0, sizeof (struct msghdr));
+
+        if (address != NULL)
+        {
+            memset (& sin, 0, sizeof (struct sockaddr_in));
+
+            sin.sin_family = AF_INET;
+            sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+            sin.sin_addr.s_addr = address -> host;
+
+            msgHdr.msg_name = & sin;
+            msgHdr.msg_namelen = sizeof (struct sockaddr_in);
+        }
+
+        msgHdr.msg_iov = (struct iovec *) buffers;
+        msgHdr.msg_iovlen = bufferCount;
+
+        sentLength = sendmsg (socket, & msgHdr, MSG_NOSIGNAL);
+
+        if (sentLength == -1)
+        {
+           if (errno == EWOULDBLOCK)
+             return 0;
+
+           return -1;
+        }
+
+        return sentLength;
+    }
+
+    int
+    enet_socket_receive (ENetSocket socket,
+                         ENetAddress * address,
+                         ENetBuffer * buffers,
+                         size_t bufferCount)
+    {
+        struct msghdr msgHdr;
+        struct sockaddr_in sin;
+        int recvLength;
+
+        memset (& msgHdr, 0, sizeof (struct msghdr));
+
+        if (address != NULL)
+        {
+            msgHdr.msg_name = & sin;
+            msgHdr.msg_namelen = sizeof (struct sockaddr_in);
+        }
+
+        msgHdr.msg_iov = (struct iovec *) buffers;
+        msgHdr.msg_iovlen = bufferCount;
+
+        recvLength = recvmsg (socket, & msgHdr, MSG_NOSIGNAL);
+
+        if (recvLength == -1)
+        {
+           if (errno == EWOULDBLOCK)
+             return 0;
+
+           return -1;
+        }
+
+    #ifdef HAS_MSGHDR_FLAGS
+        if (msgHdr.msg_flags & MSG_TRUNC)
+          return -1;
+    #endif
+
+        if (address != NULL)
+        {
+            address -> host = (enet_uint32) sin.sin_addr.s_addr;
+            address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+        }
+
+        return recvLength;
+    }
+
+    int
+    enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout)
+    {
+        struct timeval timeVal;
+
+        timeVal.tv_sec = timeout / 1000;
+        timeVal.tv_usec = (timeout % 1000) * 1000;
+
+        return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal);
+    }
+
+    int
+    enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint64 timeout)
+    {
+    #ifdef HAS_POLL
+        struct pollfd pollSocket;
+        int pollCount;
+
+        pollSocket.fd = socket;
+        pollSocket.events = 0;
+
+        if (* condition & ENET_SOCKET_WAIT_SEND)
+          pollSocket.events |= POLLOUT;
+
+        if (* condition & ENET_SOCKET_WAIT_RECEIVE)
+          pollSocket.events |= POLLIN;
+
+        pollCount = poll (& pollSocket, 1, timeout);
+
+        if (pollCount < 0)
+        {
+            if (errno == EINTR && * condition & ENET_SOCKET_WAIT_INTERRUPT)
+            {
+                * condition = ENET_SOCKET_WAIT_INTERRUPT;
+
+                return 0;
+            }
+
+            return -1;
+        }
+
+        * condition = ENET_SOCKET_WAIT_NONE;
+
+        if (pollCount == 0)
+          return 0;
+
+        if (pollSocket.revents & POLLOUT)
+          * condition |= ENET_SOCKET_WAIT_SEND;
+
+        if (pollSocket.revents & POLLIN)
+          * condition |= ENET_SOCKET_WAIT_RECEIVE;
+
+        return 0;
+    #else
+        fd_set readSet, writeSet;
+        struct timeval timeVal;
+        int selectCount;
+
+        timeVal.tv_sec = timeout / 1000;
+        timeVal.tv_usec = (timeout % 1000) * 1000;
+
+        FD_ZERO (& readSet);
+        FD_ZERO (& writeSet);
+
+        if (* condition & ENET_SOCKET_WAIT_SEND)
+          FD_SET (socket, & writeSet);
+
+        if (* condition & ENET_SOCKET_WAIT_RECEIVE)
+          FD_SET (socket, & readSet);
+
+        selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal);
+
+        if (selectCount < 0)
+        {
+            if (errno == EINTR && * condition & ENET_SOCKET_WAIT_INTERRUPT)
+            {
+                * condition = ENET_SOCKET_WAIT_INTERRUPT;
+
+                return 0;
+            }
+
+            return -1;
+        }
+
+        * condition = ENET_SOCKET_WAIT_NONE;
+
+        if (selectCount == 0)
+          return 0;
+
+        if (FD_ISSET (socket, & writeSet))
+          * condition |= ENET_SOCKET_WAIT_SEND;
+
+        if (FD_ISSET (socket, & readSet))
+          * condition |= ENET_SOCKET_WAIT_RECEIVE;
+
+        return 0;
+    #endif
+    }
+
+    #endif
+
+    // @from_file: win32.c
+    /**
+     @file  win32.c
+     @brief ENet Win32 system specific functions
+    */
+    #ifdef _WIN32
+
+    #define ENET_BUILDING_LIB 1
+
+    #include <windows.h>
+    #include <mmsystem.h>
+
+    static enet_uint64 timeBase = 0;
+
+    int
+    enet_initialize (void)
+    {
+        WORD versionRequested = MAKEWORD (1, 1);
+        WSADATA wsaData;
+
+        if (WSAStartup (versionRequested, & wsaData))
+           return -1;
+
+        if (LOBYTE (wsaData.wVersion) != 1||
+            HIBYTE (wsaData.wVersion) != 1)
+        {
+           WSACleanup ();
+
+           return -1;
+        }
+
+        timeBeginPeriod (1);
+
+        return 0;
+    }
+
+    void
+    enet_deinitialize (void)
+    {
+        timeEndPeriod (1);
+
+        WSACleanup ();
+    }
+
+    enet_uint64
+    enet_host_random_seed (void)
+    {
+        return (enet_uint64) timeGetTime ();
+    }
+
+    enet_uint64
+    enet_time_get (void)
+    {
+        return (enet_uint64) timeGetTime () - timeBase;
+    }
+
+    void
+    enet_time_set (enet_uint64 newTimeBase)
+    {
+        timeBase = (enet_uint64) timeGetTime () - newTimeBase;
+    }
+
+    int
+    enet_address_set_host_ip (ENetAddress * address, const char * name)
+    {
+        enet_uint8 vals [4] = { 0, 0, 0, 0 };
+        int i;
+
+        for (i = 0; i < 4; ++ i)
+        {
+            const char * next = name + 1;
+            if (* name != '0')
+            {
+                long val = strtol (name, (char **) & next, 10);
+                if (val < 0 || val > 255 || next == name || next - name > 3)
+                  return -1;
+                vals [i] = (enet_uint8) val;
+            }
+
+            if (* next != (i < 3 ? '.' : '\0'))
+              return -1;
+            name = next + 1;
+        }
+
+        memcpy (& address -> host, vals, sizeof (enet_uint32));
+        return 0;
+    }
+
+    int
+    enet_address_set_host (ENetAddress * address, const char * name)
+    {
+        struct hostent * hostEntry;
+
+        hostEntry = gethostbyname (name);
+        if (hostEntry == NULL ||
+            hostEntry -> h_addrtype != AF_INET)
+          return enet_address_set_host_ip (address, name);
+
+        address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
+
+        return 0;
+    }
+
+    int
+    enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
+    {
+        char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
+        if (addr == NULL)
+            return -1;
+        else
+        {
+            size_t addrLen = strlen(addr);
+            if (addrLen >= nameLength)
+              return -1;
+            memcpy (name, addr, addrLen + 1);
+        }
+        return 0;
+    }
+
+    int
+    enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
+    {
+        struct in_addr in;
+        struct hostent * hostEntry;
+
+        in.s_addr = address -> host;
+
+        hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
+        if (hostEntry == NULL)
+          return enet_address_get_host_ip (address, name, nameLength);
+        else
+        {
+           size_t hostLen = strlen (hostEntry -> h_name);
+           if (hostLen >= nameLength)
+             return -1;
+           memcpy (name, hostEntry -> h_name, hostLen + 1);
+        }
+
+        return 0;
+    }
+
+    int
+    enet_socket_bind (ENetSocket socket, const ENetAddress * address)
+    {
+        struct sockaddr_in sin;
+
+        memset (& sin, 0, sizeof (struct sockaddr_in));
+
+        sin.sin_family = AF_INET;
+
+        if (address != NULL)
+        {
+           sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+           sin.sin_addr.s_addr = address -> host;
+        }
+        else
+        {
+           sin.sin_port = 0;
+           sin.sin_addr.s_addr = INADDR_ANY;
+        }
+
+        return bind (socket,
+                     (struct sockaddr *) & sin,
+                     sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0;
+    }
+
+    int
+    enet_socket_get_address (ENetSocket socket, ENetAddress * address)
+    {
+        struct sockaddr_in sin;
+        int sinLength = sizeof (struct sockaddr_in);
+
+        if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
+          return -1;
+
+        address -> host = (enet_uint32) sin.sin_addr.s_addr;
+        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+
+        return 0;
+    }
+
+    int
+    enet_socket_listen (ENetSocket socket, int backlog)
+    {
+        return listen (socket, backlog < 0 ? SOMAXCONN : backlog) == SOCKET_ERROR ? -1 : 0;
+    }
+
+    ENetSocket
+    enet_socket_create (ENetSocketType type)
+    {
+        return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
+    }
+
+    int
+    enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
+    {
+        int result = SOCKET_ERROR;
+        switch (option)
+        {
+            case ENET_SOCKOPT_NONBLOCK:
+            {
+                u_long nonBlocking = (u_long) value;
+                result = ioctlsocket (socket, FIONBIO, & nonBlocking);
+                break;
+            }
+
+            case ENET_SOCKOPT_BROADCAST:
+                result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_REUSEADDR:
+                result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_RCVBUF:
+                result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_SNDBUF:
+                result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_RCVTIMEO:
+                result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_SNDTIMEO:
+                result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & value, sizeof (int));
+                break;
+
+            case ENET_SOCKOPT_NODELAY:
+                result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int));
+                break;
+
+            default:
+                break;
+        }
+        return result == SOCKET_ERROR ? -1 : 0;
+    }
+
+    int
+    enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value)
+    {
+        int result = SOCKET_ERROR, len;
+        switch (option)
+        {
+            case ENET_SOCKOPT_ERROR:
+                len = sizeof(int);
+                result = getsockopt (socket, SOL_SOCKET, SO_ERROR, (char *) value, & len);
+                break;
+
+            default:
+                break;
+        }
+        return result == SOCKET_ERROR ? -1 : 0;
+    }
+
+    int
+    enet_socket_connect (ENetSocket socket, const ENetAddress * address)
+    {
+        struct sockaddr_in sin;
+        int result;
+
+        memset (& sin, 0, sizeof (struct sockaddr_in));
+
+        sin.sin_family = AF_INET;
+        sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+        sin.sin_addr.s_addr = address -> host;
+
+        result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
+        if (result == SOCKET_ERROR && WSAGetLastError () != WSAEWOULDBLOCK)
+          return -1;
+
+        return 0;
+    }
+
+    ENetSocket
+    enet_socket_accept (ENetSocket socket, ENetAddress * address)
+    {
+        SOCKET result;
+        struct sockaddr_in sin;
+        int sinLength = sizeof (struct sockaddr_in);
+
+        result = accept (socket,
+                         address != NULL ? (struct sockaddr *) & sin : NULL,
+                         address != NULL ? & sinLength : NULL);
+
+        if (result == INVALID_SOCKET)
+          return ENET_SOCKET_NULL;
+
+        if (address != NULL)
+        {
+            address -> host = (enet_uint32) sin.sin_addr.s_addr;
+            address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+        }
+
+        return result;
+    }
+
+    int
+    enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how)
+    {
+        return shutdown (socket, (int) how) == SOCKET_ERROR ? -1 : 0;
+    }
+
+    void
+    enet_socket_destroy (ENetSocket socket)
+    {
+        if (socket != INVALID_SOCKET)
+          closesocket (socket);
+    }
+
+    int
+    enet_socket_send (ENetSocket socket,
+                      const ENetAddress * address,
+                      const ENetBuffer * buffers,
+                      size_t bufferCount)
+    {
+        struct sockaddr_in sin;
+        DWORD sentLength;
+
+        if (address != NULL)
+        {
+            memset (& sin, 0, sizeof (struct sockaddr_in));
+
+            sin.sin_family = AF_INET;
+            sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+            sin.sin_addr.s_addr = address -> host;
+        }
+
+        if (WSASendTo (socket,
+                       (LPWSABUF) buffers,
+                       (DWORD) bufferCount,
+                       & sentLength,
+                       0,
+                       address != NULL ? (struct sockaddr *) & sin : NULL,
+                       address != NULL ? sizeof (struct sockaddr_in) : 0,
+                       NULL,
+                       NULL) == SOCKET_ERROR)
+        {
+           if (WSAGetLastError () == WSAEWOULDBLOCK)
+             return 0;
+
+           return -1;
+        }
+
+        return (int) sentLength;
+    }
+
+    int
+    enet_socket_receive (ENetSocket socket,
+                         ENetAddress * address,
+                         ENetBuffer * buffers,
+                         size_t bufferCount)
+    {
+        INT sinLength = sizeof (struct sockaddr_in);
+        DWORD flags = 0,
+              recvLength;
+        struct sockaddr_in sin;
+
+        if (WSARecvFrom (socket,
+                         (LPWSABUF) buffers,
+                         (DWORD) bufferCount,
+                         & recvLength,
+                         & flags,
+                         address != NULL ? (struct sockaddr *) & sin : NULL,
+                         address != NULL ? & sinLength : NULL,
+                         NULL,
+                         NULL) == SOCKET_ERROR)
+        {
+           switch (WSAGetLastError ())
+           {
+           case WSAEWOULDBLOCK:
+           case WSAECONNRESET:
+              return 0;
+           }
+
+           return -1;
+        }
+
+        if (flags & MSG_PARTIAL)
+          return -1;
+
+        if (address != NULL)
+        {
+            address -> host = (enet_uint32) sin.sin_addr.s_addr;
+            address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+        }
+
+        return (int) recvLength;
+    }
+
+    int
+    enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout)
+    {
+        struct timeval timeVal;
+
+        timeVal.tv_sec = timeout / 1000;
+        timeVal.tv_usec = (timeout % 1000) * 1000;
+
+        return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal);
+    }
+
+    int
+    enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint64 timeout)
+    {
+        fd_set readSet, writeSet;
+        struct timeval timeVal;
+        int selectCount;
+
+        timeVal.tv_sec = timeout / 1000;
+        timeVal.tv_usec = (timeout % 1000) * 1000;
+
+        FD_ZERO (& readSet);
+        FD_ZERO (& writeSet);
+
+        if (* condition & ENET_SOCKET_WAIT_SEND)
+          FD_SET (socket, & writeSet);
+
+        if (* condition & ENET_SOCKET_WAIT_RECEIVE)
+          FD_SET (socket, & readSet);
+
+        selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal);
+
+        if (selectCount < 0)
+          return -1;
+
+        * condition = ENET_SOCKET_WAIT_NONE;
+
+        if (selectCount == 0)
+          return 0;
+
+        if (FD_ISSET (socket, & writeSet))
+          * condition |= ENET_SOCKET_WAIT_SEND;
+
+        if (FD_ISSET (socket, & readSet))
+          * condition |= ENET_SOCKET_WAIT_RECEIVE;
+
+        return 0;
+    }
+
+    #endif
+    #ifdef __cplusplus
+    }
+    #endif
+
+#endif
+
+#endif /* __ENET_ENET_H__ */

+ 2 - 0
include/enet/enet.h

@@ -21,6 +21,8 @@ extern "C"
 #include "enet/types.h"
 #include "enet/protocol.h"
 #include "enet/list.h"
+#include "enet/time.h"
+#include "enet/utility.h"
 #include "enet/callbacks.h"
 
 #define ENET_VERSION_MAJOR 1

+ 0 - 10
libenet.pc.in

@@ -1,10 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: @PACKAGE_NAME@
-Description: Low-latency UDP networking library supporting optional reliability
-Version: @PACKAGE_VERSION@
-Cflags: -I${includedir}
-Libs: -L${libdir} -lenet

+ 0 - 0
m4/.keep


+ 0 - 0
ChangeLog → misc/ChangeLog


+ 124 - 0
misc/build-singleheader.js

@@ -0,0 +1,124 @@
+const fs = require('fs')
+
+function read_file(name) {
+    return fs
+        .readFileSync(name)
+        .toString('utf-8')
+        .trim()
+}
+
+function include_enet(src) {
+    return src
+        .split('\n')
+        .map(line => {
+            if (line.indexOf('#include "enet/') !== -1) {
+                return read_file('include/' + line.slice(10, -1))
+            }
+
+            return line
+        })
+        .join('\n')
+}
+
+function filter_libs(src, unqiue_lib_list) {
+    return src
+        .split('\n')
+        .map((line, i) => {
+            if (line.indexOf('#include "enet/') !== -1) {
+                return ''
+            }
+
+            if (line.indexOf('#include <') !== -1) {
+                if (!unqiue_lib_list[line.slice(10, -1)]) {
+                    unqiue_lib_list[line.slice(10, -1)] = 1;
+                    return line
+                } else {
+                    unqiue_lib_list[line.slice(10, -1)]++
+                    return ''
+                }
+            }
+
+            return line.replace(/\s*$/, '')
+        })
+        .join('\n')
+}
+
+function attach_src(src, unqiue_lib_list, sources_list, scr_template) {
+    let files = sources_list
+        .map(file => {
+            return '\n// @from_file: ' + file + '\n' +
+                filter_libs(read_file(file), unqiue_lib_list)
+        })
+        .join('\n')
+
+    // add 4 spaces in front
+    files = files
+        .split('\n')
+        .map(line => line !== '' ? "    " + line : line)
+        .join('\n')
+
+    src = src.replace('#endif /* __ENET_ENET_H__ */', '')
+    src = src + scr_template[0] + files + scr_template[1]
+
+    return src
+}
+
+let sources = [
+    'callbacks.c',
+    'compress.c',
+    'host.c',
+    'list.c',
+    'packet.c',
+    'peer.c',
+    'protocol.c',
+    'unix.c',
+    'win32.c',
+]
+
+let scr_template = [
+`
+#if defined(ENET_IMPLEMENTATION) && !defined(ENET_IMPLEMENTATION_DONE)
+#define ENET_IMPLEMENTATION_DONE
+
+    #define ENET_BUILDING_LIB 1
+
+    #ifdef __cplusplus
+    extern "C"
+    {
+    #endif
+`,
+    // code there
+`
+    #ifdef __cplusplus
+    }
+    #endif
+
+#endif
+
+#endif /* __ENET_ENET_H__ */
+`];
+
+let prefix =
+`/**
+ * include/enet.h - a Single-Header auto-generated variant of enet.h library.
+ *
+ * Usage:
+ * #define ENET_IMPLEMENTATION exactly in ONE source file right BEFORE including the library, like:
+ *
+ * #define ENET_IMPLEMENTATION
+ * #include <enet.h>
+ *
+ */
+
+`;
+
+(function main() {
+    let list = {};
+    let src  = read_file('include/enet/enet.h')
+
+    src = include_enet(src)
+    src = filter_libs(src, list)
+    src = attach_src(src, list, sources, scr_template)
+
+    fs.writeFileSync('include/enet.h', prefix + src)
+})();

+ 57 - 58
premake4.lua

@@ -1,59 +1,58 @@
 solution "enet"
-	configurations { "Debug", "Release" }
-	platforms { "x32", "x64" }
-
-	project "enet_static"
-		kind "StaticLib"
-		language "C"
-		
-		files { "*.c" }
-		
-		includedirs { "include/" }
-		
-		configuration "Debug"
-			targetsuffix "d"
-			
-			defines({ "DEBUG" })
-
-			flags { "Symbols" }
-		
-		configuration "Release"
-			defines({ "NDEBUG" })
-
-			flags { "Optimize" }
-			
-		configuration { "Debug", "x64" }
-			targetsuffix "64d"
-			
-		configuration { "Release", "x64" }
-			targetsuffix "64"
-
-	project "enet"
-		kind "SharedLib"
-		language "C"
-		
-		files { "*.c" }
-		
-		includedirs { "include/" }
-		
-		defines({"ENET_DLL=1" })
-		
-		configuration "Debug"
-			targetsuffix "d"
-			
-			defines({ "DEBUG" })
-
-			flags { "Symbols" }
-		
-		configuration "Release"
-			defines({ "NDEBUG" })
-
-			flags { "Optimize" }
-			
-		configuration { "Debug", "x64" }
-			targetsuffix "64d"
-			
-		configuration { "Release", "x64" }
-			targetsuffix "64"
-
-		
+    configurations { "Debug", "Release" }
+    platforms { "x32", "x64" }
+
+    project "enet_static"
+        kind "StaticLib"
+        language "C"
+
+        files { "*.c" }
+
+        includedirs { "include/" }
+
+        configuration "Debug"
+            targetsuffix "d"
+
+            defines({ "DEBUG" })
+
+            flags { "Symbols" }
+
+        configuration "Release"
+            defines({ "NDEBUG" })
+
+            flags { "Optimize" }
+
+        configuration { "Debug", "x64" }
+            targetsuffix "64d"
+
+        configuration { "Release", "x64" }
+            targetsuffix "64"
+
+    project "enet"
+        kind "SharedLib"
+        language "C"
+
+        files { "*.c" }
+
+        includedirs { "include/" }
+
+        defines({"ENET_DLL=1" })
+
+        configuration "Debug"
+            targetsuffix "d"
+
+            defines({ "DEBUG" })
+
+            flags { "Symbols" }
+
+        configuration "Release"
+            defines({ "NDEBUG" })
+
+            flags { "Optimize" }
+
+        configuration { "Debug", "x64" }
+            targetsuffix "64d"
+
+        configuration { "Release", "x64" }
+            targetsuffix "64"
+

+ 9 - 0
test/build.c

@@ -0,0 +1,9 @@
+#define ENET_IMPLEMENTATION
+#include <enet.h>
+
+int main() {
+    enet_initialize();
+    enet_deinitialize();
+
+    return 0;
+}