Storyboard events contain string based names and a variable data field.  For
                    this reason the event data must be serialized into a buffer for communication.
                     The Storyboard IO API provides the functions needed to both serialize your data
                    and send the event.  The event you wish to send must first be serialized via a
                    call to gre_io_serialize().  This will allocated a serialized data
                    buffer for your event.  The event can then be sent via the
                        gre_io_send() function.  Once the event has been sent the
                    buffer can be reused or freed via a call to
                    gre_io_free_buffer().
Serialized buffers can be reused multiple times. The
                            gre_io_serialize_buffer() function will resize or
                        reallocate the buffer if the data being serialized is larger than the
                        existing buffer. This is designed to cut down on repetitive memory
                        allocation and deallocation churn.
Data parameters must be sent in order of descending alignment requirements. Example: 4u1 4u1 2u1 1s0 is good, 2u1 4u1 4u1 1s0 is not
gre_io_t                    *send_handle;
gre_io_serialized_data_t    *nbuffer = NULL;
const char                  *event_data = "my event data"
/*
 * Connect to a channel to send messages.
 */
send_handle = gre_io_open("my_channel", GRE_IO_TYPE_WRONLY);
if(send_handle == NULL) {
    printf("Can't open send handle [%s]\n", argv[1]);
    return 0;
}
/*
 * Send a named event containing no data payload
 */
nbuffer = gre_io_serialize(nbuffer, NULL,
             "my_event_name",
             NULL,
             NULL,
             0);
gre_io_send(send_handle, nbuffer);
/*
 * Send a named event with an additional string payload
 */
nbuffer = gre_io_serialize(nbuffer, NULL,
             "my_event_name",
             "1s0 data",
             event_data,
             strlen(event_data)+1);
gre_io_send(send_handle, nbuffer);
               New events can be readily defined and are not required to contain
                                a data payload. In this case their format string and data payload
                                will be empty values.  When creating new events, it is appropriate
                                to namespace the event definitions so that the names of events do
                                not collide.  For example, the Storyboard framework reserves the
                                name prefix of gre. for user interface events, and the
                                timer functions all generate events that are prefixed with
                                    timer.
The use of events is closely coupled with the declaration and operation of actions. An action can only be invoked when an event matching the action definition is received. This results in a common design pattern where an action will perform sophisticated logic in an external script or program and then signal a completion action to run once the script work is complete.
Event >Action (script) >Work >Trigger Event >Action (completion)
The format string on the event is used to assist with decoding event data. This decoding is used in the action bindings, to allow a minimal amount of additional logic to be placed into the event matching code, and also by certain advanced actions, such as Lua scripts, that can symbolically access the event data in the context of the script.
The format string provides a description of how to interpret the
								memory block (typically a data structure) that is associated with
								the event as its data payload. The format string is relatively
								straightforward to create and uses blocks that are formatted as
                                    [numbytes][signed/unsigned][numelements][ ][name].
                                For the standard C data types the number formatting would look
                                like:
1s0 --> Special null terminated string 1s1|1u1 --> 1 byte integer (int8_t uint8_t) 2s1|2u1 --> 2 byte integer (int16_t uint16_t) 4s1|4u1 --> 4 byte integer (int32_t uint32_t) 4f1 --> 4 byte floating point (IEEE754 float) 8s1|8u1 --> 8 byte integer (int64_t uint64_t)
So, if you were transmitting a structure such as:
struct {
    int32_t    a;
    uint16_t   b;
};
Which is assumed to have a bytewise memory layout of:
[a|a|a|a|b|b]
You would use a format string of 4s1 a 2u1 b to describe the event.  
The event data field descriptions a and
                                    b are optional.  They are used to give the data
								symbolic representation for clients and do not have to be named to match
                                the C structure field values. The descriptions are used by clients
                                of the event data to symbolically access the event data. The Lua
                                script plugin, for example, will use the symbolic name information
                                as keys to a table that stores the event data content, appropriately
                                decoded based on the format string definition.
The format string provided describes the memory layout of the data associated with the event. Consequently it is important that the format string compensate for any alignment or compiler padding provided by inserting appropriate additional format entries to skip over unused bytes. This may require slight adjustments to the format string based on the CPU architecture or compiler settings regarding C structure alignment.