From b642f672f00986106dfde4dbfa3fc7851c9a9622 Mon Sep 17 00:00:00 2001
From: Katie McCormick
Date: Fri, 17 Jan 2014 13:06:12 -0800
Subject: Doc change: Update CCS doc with new quota info.
Fix for:
b/12665669
Change-Id: I08f812d37ab6f4347f6401b3a9682c45d96adb81
---
docs/html/google/gcm/ccs.jd | 152 +--
docs/html/images/gcm/CCS-ack.png | Bin 55599 -> 54832 bytes
docs/image_sources/gcm/CCS-ack.graffle | 1580 ++++++++++++++++++++++++++++++++
3 files changed, 1677 insertions(+), 55 deletions(-)
create mode 100644 docs/image_sources/gcm/CCS-ack.graffle
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index d2177ca8a897..03addfdb6f60 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -8,7 +8,7 @@ page.title=GCM Cloud Connection Server (XMPP)
In this document
- - How to Use CCS
+
- Establishing a Connection
- Authentication
@@ -46,19 +46,20 @@ target="_android">CCS and User Notifications Signup Form
Note: To try out this feature, sign up using
this form.
-The GCM Cloud Connection Server (CCS) is a connection server based on XMPP.
-CCS allows 3rd-party app servers (which you're
-responsible for implementing) to communicate
-with Android devices by establishing a persistent TCP connection with Google
-servers using the XMPP protocol. This communication is asynchronous and bidirectional.
+The GCM Cloud Connection Server (CCS) is an XMPP endpoint that provides a
+persistent, asynchronous, bidirectional connection to Google servers. The
+connection can be used to send and receive messages between your server and
+your users' GCM-connected devices.
+
You can continue to use the HTTP request mechanism to send messages to GCM
servers, side-by-side with CCS which uses XMPP. Some of the benefits of CCS include:
+
- The asynchronous nature of XMPP allows you to send more messages with fewer
resources.
- - Communication is bidirectional—not only can the server send messages
-to the device, but the device can send messages back to the server.
-- You can send messages back using the same connection used for receiving,
+
- Communication is bidirectional—not only can your server send messages
+to the device, but the device can send messages back to your server.
+ - The device can send messages back using the same connection used for receiving,
thereby improving battery life.
@@ -73,22 +74,34 @@ APIs. For examples, see
Implementing GCM Server for a list of all the message
parameters and which connection server(s) supports them.
+Establishing a Connection
-How to Use CCS
+CCS just uses XMPP as an authenticated transport layer, so you can use most
+XMPP libraries to manage the connection. For an example, see
+Java sample using the Smack library.
-GCM Cloud Connection Server (CCS) is an XMPP endpoint, running on
-{@code http://gcm.googleapis.com} port 5235.
+The CCS XMPP endpoint runs at {@code gcm.googleapis.com:5235}. When testing
+functionality (with non-production users), you should instead connect to
+{@code gcm-staging.googleapis.com:5236} (note the different port). Testing on
+staging (a smaller environment where the latest CCS builds run) is beneficial
+both for isolating real users from test code, as well as for early detection of
+unexpected behavior changes.
-CCS requires a Transport Layer Security (TLS) connection. That means the XMPP
-client must initiate a TLS connection.
-For example in Java, you would call {@code setSocketFactory(SSLSocketFactory)}.
+The connection has two important requirements:
-CCS requires a SASL PLAIN authentication mechanism using
-{@code <your_GCM_Sender_Id>@gcm.googleapis.com} (GCM sender ID) and the
-API key as the password, where the sender ID and API key are the same as described
-in Getting Started.
+
+ - You must initiate a Transport Layer Security (TLS) connection. Note that
+ CCS doesn't currently support the STARTTLS extension.
+ - CCS requires a SASL PLAIN authentication mechanism using
+ {@code <your_GCM_Sender_Id>@gcm.googleapis.com} (GCM sender ID)
+ and the API key as the password, where the sender ID and API key are the same
+ as described in Getting Started.
+
- You can use most XMPP libraries to interact with CCS.
+If at any point the connection fails, you should immediately reconnect.
+There is no need to back off after a disconnect that happens after
+authentication.
Authentication
@@ -100,11 +113,11 @@ in Getting Started.
Server
<str:features xmlns:str="http://etherx.jabber.org/streams">
- <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
- <mechanism>X-OAUTH2</mechanism>
- <mechanism>X-GOOGLE-TOKEN</mechanism>
- <mechanism>PLAIN</mechanism>
- </mechanisms>
+ <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
+ <mechanism>X-OAUTH2</mechanism>
+ <mechanism>X-GOOGLE-TOKEN</mechanism>
+ <mechanism>PLAIN</mechanism>
+ </mechanisms>
</str:features>
@@ -118,16 +131,18 @@ mFTeUIzcmNaTmtmbnFLZEZiOW1oekNCaVlwT1JEQTJKV1d0dw==</auth>
<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
-CCS uses normal XMPP <message> stanzas. The body of the message must be:
-
+Once the XMPP connection is established, CCS and your server use normal XMPP
+<message> stanzas to send JSON-encoded messages back and
+forth. The body of the <message> must be:
<gcm xmlns:google:mobile:data>
JSON payload
</gcm>
-The JSON payload for server-to-device is similar to what the GCM http endpoint
-uses, with these exceptions:
+The JSON payload for regular GCM messages is similar to
+what the GCM http endpoint uses, with these
+exceptions:
- There is no support for multiple recipients.
- {@code to} is used instead of {@code registration_ids}.
@@ -136,14 +151,13 @@ identifies the message in an XMPP connection. The ACK or NACK from CCS uses the
{@code message_id} to identify a message sent from 3rd-party app servers to CCS.
Therefore, it's important that this {@code message_id} not only be unique, but
always present.
+
-For ACK/NACK messages that are special control messages, you also need to
-include a {@code message_type} field in the JSON message. The value can be either
-'ack' or 'nack'. For example:
+In addition to regular GCM messages, control messages are sent, indicated by
+the {@code message_type} field in the JSON object. The value can be either
+'ack' or 'nack', or 'control' (see formats below). Any GCM message with an
+unknown {@code message_type} can be ignored by your server.
-message_type = ('ack');
-
-
For each device message your app server receives from CCS, it needs to send
an ACK message.
It never needs to send a NACK message. If you don't send an ACK for a message,
@@ -251,7 +265,9 @@ message is "nack". A NACK message contains:
</message>
-The following table lists some of the more common NACK error codes.
+The following table lists NACK error codes. Unless otherwise
+indicated, a NACKed message should not be retried. Unexpected NACK error codes
+should be treated the same as {@code INTERNAL_SERVER_ERROR}.
Table 1. NACK error codes.
@@ -262,8 +278,17 @@ message is "nack". A NACK message contains:
Description |
+| {@code BAD_ACK} |
+The ACK message is improperly formed. |
+
+
| {@code BAD_REGISTRATION} |
-The device has a registration ID, but it's invalid. |
+The device has a registration ID, but it's invalid or expired. |
+
+
+| {@code CONNECTION_DRAINING} |
+The message couldn't be processed because the connection is draining. The
+message should be immediately retried over another connection. |
| {@code DEVICE_UNREGISTERED} |
@@ -274,25 +299,20 @@ message is "nack". A NACK message contains:
The server encountered an error while trying to process the request. |
-| {@code SERVICE_UNAVAILABLE} |
-The CCS connection server is temporarily unavailable, try again later
-(using exponential backoff, etc.). |
+{@code INVALID_JSON} |
+The JSON message payload was not valid. |
-| {@code BAD_ACK} |
-The ACK message is improperly formed. |
-
-
-| {@code AUTHENTICATION_FAILED} |
-This is a 401 error indicating that there was an error authenticating the sender account. |
-
-
-| {@code INVALID_TTL} |
-There was an error in the supplied "time to live" value. |
+{@code QUOTA_EXCEEDED} |
+The rate of messages to a particular registration ID (in other words, to a
+sender/device pair) is too high. If you want to retry the message, try using a slower
+rate. |
-| {@code JSON_TYPE_ERROR} |
-There was an error in the supplied JSON data type. |
+{@code SERVICE_UNAVAILABLE} |
+CCS is not currently able to process the message. The
+message should be retried over the same connection using exponential backoff
+with an initial delay of 1 second. |
@@ -319,6 +339,28 @@ A stanza error contains:
</message>
+Control messages
+
+Periodically, CCS needs to close down a connection to perform load balancing. Before it
+closes the connection, CCS sends a {@code CONNECTION_DRAINING} message to indicate that the connection is being drained
+and will be closed soon. "Draining" refers to shutting off the flow of messages coming into a
+connection, but allowing whatever is already in the pipeline to continue. When you receive
+a {@code CONNECTION_DRAINING} message, you should immediately begin sending messages to another CCS
+connection, opening a new connection if necessary. You should, however, keep the original
+connection open and continue receiving messages that may come over the connection (and
+ACKing them)—CCS will handle initiating a connection close when it is ready.
+
+The {@code CONNECTION_DRAINING} message looks like this:
+<message>
+ <data:gcm xmlns:data="google:mobile:data">
+ {
+ "message_type":"control"
+ "control_type":"CONNECTION_DRAINING"
+ }
+ </data:gcm>
+</message>
+
+{@code CONNECTION_DRAINING} is currently the only {@code control_type} supported.
Upstream Messages
@@ -381,7 +423,7 @@ response to the above message:
Every message sent to CCS receives either an ACK or a NACK response. Messages
that haven't received one of these responses are considered pending. If the pending
-message count reaches 1000, the 3rd-party app server should stop sending new messages
+message count reaches 100, the 3rd-party app server should stop sending new messages
and wait for CCS to acknowledge some of the existing pending messages as illustrated in
figure 1:
@@ -395,7 +437,7 @@ figure 1:
if there are too many unacknowledged messages. Therefore, the 3rd-party app server
should "ACK" upstream messages, received from the client application via CCS, as soon as possible
to maintain a constant flow of incoming messages. The aforementioned pending message limit doesn't
-apply to these ACKs. Even if the pending message count reaches 1000, the 3rd-party app server
+apply to these ACKs. Even if the pending message count reaches 100, the 3rd-party app server
should continue sending ACKs for messages received from CCS to avoid blocking delivery of new
upstream messages.
@@ -795,7 +837,7 @@ USERNAME = "Your GCM Sender Id"
PASSWORD = "API Key"
REGISTRATION_ID = "Registration Id of the target device"
-unacked_messages_quota = 1000
+unacked_messages_quota = 100
send_queue = []
# Return a random alphanumerical id
diff --git a/docs/html/images/gcm/CCS-ack.png b/docs/html/images/gcm/CCS-ack.png
index bce2ab2f5a1d..4633157a7067 100644
Binary files a/docs/html/images/gcm/CCS-ack.png and b/docs/html/images/gcm/CCS-ack.png differ
diff --git a/docs/image_sources/gcm/CCS-ack.graffle b/docs/image_sources/gcm/CCS-ack.graffle
new file mode 100644
index 000000000000..addd456861fa
--- /dev/null
+++ b/docs/image_sources/gcm/CCS-ack.graffle
@@ -0,0 +1,1580 @@
+
+
+
+
+ ActiveLayerIndex
+ 0
+ ApplicationVersion
+
+ com.omnigroup.OmniGrafflePro
+ 139.18.0.187838
+
+ AutoAdjust
+
+ BackgroundGraphic
+
+ Bounds
+ {{0, 0}, {576.00002479553223, 733}}
+ Class
+ SolidGraphic
+ FontInfo
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 2
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+
+ BaseZoom
+ 0
+ CanvasOrigin
+ {0, 0}
+ ColumnAlign
+ 1
+ ColumnSpacing
+ 36
+ CreationDate
+ 2013-08-08 01:54:22 +0000
+ Creator
+ Katie McCormick
+ DisplayScale
+ 1 0/72 in = 1.0000 in
+ GraphDocumentVersion
+ 8
+ GraphicsList
+
+
+ Bounds
+ {{89, 329}, {169, 44}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ ID
+ 250
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 Now app server can send\
+message no. 101}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{102, 266}, {114, 44}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ ID
+ 249
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 App server waits\
+for ack 1}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{153, 154}, {98, 44}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ ID
+ 244
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 Average\
+response time}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ Head
+
+ ID
+ 226
+ Position
+ 0.375
+
+ ID
+ 242
+ Points
+
+ {263.00000095367432, 314.5}
+ {261, 99}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.112257
+ g
+ 0.107007
+ r
+ 0.934433
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+ Tail
+
+ ID
+ 227
+ Position
+ 0.34722220897674561
+
+
+
+ Class
+ LineGraphic
+ Head
+
+ ID
+ 227
+ Position
+ 0.3541666567325592
+
+ ID
+ 241
+ Points
+
+ {261, 99}
+ {262.50000071525574, 314.5}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.112257
+ g
+ 0.107007
+ r
+ 0.934433
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+ Tail
+
+ ID
+ 226
+ Position
+ 0.375
+
+
+
+ Class
+ LineGraphic
+ Head
+
+ ID
+ 227
+
+ ID
+ 240
+ Points
+
+ {257.5, 336.5}
+ {288, 314.5}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.112257
+ g
+ 0.107007
+ r
+ 0.934433
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 239
+ Points
+
+ {231, 288.50000116229057}
+ {231, 251.25}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.112257
+ g
+ 0.107007
+ r
+ 0.934433
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+ Tail
+
+ ID
+ 238
+ Position
+ 0.56800001859664917
+
+
+
+ Class
+ LineGraphic
+ ID
+ 238
+ Points
+
+ {231, 253}
+ {231, 315.5}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.112257
+ g
+ 0.107007
+ r
+ 0.934433
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{476, 33}, {49, 32}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Font
+ Helvetica
+ Size
+ 18
+
+ ID
+ 230
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs36 \cf0 CCS}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{243, 35}, {101, 32}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Font
+ Helvetica
+ Size
+ 18
+
+ ID
+ 229
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs36 \cf0 App Server}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 228
+ Points
+
+ {288, 252}
+ {216, 252}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ 0
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 227
+ Points
+
+ {288, 314.5}
+ {216, 314.5}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ 0
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 226
+ Points
+
+ {288, 99}
+ {216, 99}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ 0
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{393.69128000000001, 348.37441999999999}, {57, 27}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ ID
+ 223
+ Rotation
+ 23
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 101}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{290.12054000000001, 420.17102}, {60, 27}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Font
+ Helvetica
+ Size
+ 14
+
+ ID
+ 222
+ Rotation
+ 341
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack 100}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 220
+ Points
+
+ {504, 351}
+ {288, 463}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{430.51697000000001, 279.19488999999999}, {44, 27}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Font
+ Helvetica
+ Size
+ 14
+
+ ID
+ 219
+ Rotation
+ 341
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack.. }
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{390.63733000000002, 258.42700000000002}, {44, 27}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Font
+ Helvetica
+ Size
+ 14
+
+ ID
+ 218
+ Rotation
+ 341
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack 2}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{290.74178999999998, 239.21059}, {57, 27}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ ID
+ 217
+ Rotation
+ 23
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 100}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{342.63623000000001, 185.82861}, {38, 27}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ ID
+ 216
+ Rotation
+ 18
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no...}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{361.60431, 234}, {44, 27}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Font
+ Helvetica
+ Size
+ 14
+
+ ID
+ 209
+ Rotation
+ 341
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack 1}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{351.16005999999999, 153.43960999999999}, {42, 27}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ ID
+ 172
+ Rotation
+ 18
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 2}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{363, 117}, {42, 27}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ ID
+ 171
+ Rotation
+ 18
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Draws
+ NO
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 1}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 169
+ Points
+
+ {504, 200.62189000000001}
+ {288, 312.62189000000001}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 168
+ Points
+
+ {504, 241.00763000000001}
+ {288, 353.00763000000001}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 167
+ Points
+
+ {504, 279}
+ {288, 391}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 165
+ Points
+
+ {289, 391}
+ {505, 492}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 164
+ Points
+
+ {288, 353}
+ {504, 454}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 163
+ Points
+
+ {288, 313}
+ {504, 414}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 162
+ Points
+
+ {288, 180}
+ {504, 281}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 161
+ Points
+
+ {288, 252}
+ {504, 353}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 160
+ Points
+
+ {288, 139.5}
+ {504, 240.5}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ Head
+
+ ID
+ 158
+ Position
+ 0.29398149251937866
+
+ ID
+ 159
+ Points
+
+ {288, 98.000000596046448}
+ {504, 199.00000476837158}
+
+ Style
+
+ stroke
+
+ Color
+
+ b
+ 0.934433
+ g
+ 0
+ r
+ 0.122713
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ TailArrow
+ 0
+
+
+ Tail
+
+ ID
+ 157
+ Position
+ 0.060185186564922333
+
+
+
+ Class
+ LineGraphic
+ ID
+ 158
+ Points
+
+ {504, 72}
+ {504, 504}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ 0
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 157
+ Points
+
+ {288, 72}
+ {288, 504}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ 0
+ Legacy
+
+ TailArrow
+ 0
+
+
+
+
+ GridInfo
+
+ ShowsGrid
+ YES
+
+ GuidesLocked
+ NO
+ GuidesVisible
+ YES
+ HPages
+ 1
+ ImageCounter
+ 1
+ KeepToScale
+
+ Layers
+
+
+ Lock
+ NO
+ Name
+ Layer 1
+ Print
+ YES
+ View
+ YES
+
+
+ LayoutInfo
+
+ Animate
+ NO
+ circoMinDist
+ 18
+ circoSeparation
+ 0.0
+ layoutEngine
+ dot
+ neatoSeparation
+ 0.0
+ twopiSeparation
+ 0.0
+
+ LinksVisible
+ NO
+ MagnetsVisible
+ NO
+ MasterSheets
+
+ ModificationDate
+ 2014-01-22 22:42:38 +0000
+ Modifier
+ Katie McCormick
+ NotesVisible
+ NO
+ Orientation
+ 2
+ OriginVisible
+ NO
+ PageBreaks
+ YES
+ PrintInfo
+
+ NSBottomMargin
+
+ float
+ 41
+
+ NSHorizonalPagination
+
+ int
+ 0
+
+ NSLeftMargin
+
+ float
+ 18
+
+ NSPaperSize
+
+ size
+ {612.00002479553223, 792}
+
+ NSPrintReverseOrientation
+
+ int
+ 0
+
+ NSRightMargin
+
+ float
+ 18
+
+ NSTopMargin
+
+ float
+ 18
+
+
+ PrintOnePage
+
+ ReadOnly
+ NO
+ RowAlign
+ 1
+ RowSpacing
+ 36
+ SheetTitle
+ Canvas 1
+ SmartAlignmentGuidesActive
+ YES
+ SmartDistanceGuidesActive
+ YES
+ UniqueID
+ 1
+ UseEntirePage
+
+ VPages
+ 1
+ WindowInfo
+
+ CurrentSheet
+ 0
+ ExpandedCanvases
+
+
+ name
+ Canvas 1
+
+
+ Frame
+ {{170, 139}, {1218, 882}}
+ ListView
+
+ OutlineWidth
+ 142
+ RightSidebar
+
+ ShowRuler
+
+ Sidebar
+
+ SidebarWidth
+ 120
+ VisibleRegion
+ {{40.5, 0}, {534.5, 364}}
+ Zoom
+ 2
+ ZoomValues
+
+
+ Canvas 1
+ 2
+ 1
+
+
+
+
+
--
cgit v1.2.3-59-g8ed1b