Overview.src.html
changeset 1 0f513d43130e
child 2 1693fc18292c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Overview.src.html	Thu Jun 07 08:12:58 2012 +0200
@@ -0,0 +1,601 @@
+<!doctype html>
+<html lang=en-US>
+<meta charset=utf-8>
+<title>Web Notifications</title>
+<style>
+ pre.idl { border:solid thin; background:#eee; color:#000; padding:0.5em 1em }
+ pre.idl :link, pre.idl :visited { color:inherit; background:transparent }
+ pre code { color:inherit; background:transparent }
+ pre.css { border: solid 0.0625em; background: #FFFFEE; color: black; padding: 0.5em 1em; }
+ .example { margin-left:1em; padding-left:1em; border-left:double; color:#222; background:#fcfcfc }
+ .note { margin-left:2em; font-weight:bold; font-style:italic; color:#008000 }
+ p.note::before { content:"Note: " }
+ .XXX { padding:.5em; border:solid #f00 }
+ p.XXX::before { content:"Issue: " }
+ dl.switch { padding-left:2em }
+ dl.switch > dt { text-indent:-1.5em }
+ dl.switch > dt:before { content:'\21AA'; padding:0 0.5em 0 0; display:inline-block; width:1em; text-align:right; line-height:0.5em }
+ dl.domintro { color: green; margin: 2em 0 2em 2em; padding: 0.5em 1em; border: none; background: #DDFFDD; }
+ dl.domintro dt, dl.domintro dt * { color: black; text-decoration: none; }
+ dl.domintro dd { margin: 0.5em 0 1em 2em; padding: 0; }
+ dl.domintro dd p { margin: 0.5em 0; }
+ dl.domintro:before { display: table; margin: -1em -0.5em -0.5em auto; width: auto; content: 'This box is non-normative. Implementation requirements are given below this box.'; color: red; border: solid 2px; background: white; padding: 0 0.25em; }
+ em.ct { text-transform:lowercase; font-variant:small-caps; font-style:normal }
+ dfn { font-weight:bold; font-style:normal }
+ code { color:orangered }
+ code :link, code :visited { color:inherit }
+ hr:not(.top) { display:block; background:none; border:none; padding:0; margin:2em 0; height:auto }
+ table { border-collapse:collapse; border-style:hidden hidden none hidden }
+ table thead { border-bottom:solid }
+ table tbody th:first-child { border-left:solid }
+ table td, table th { border-left:solid; border-right:solid; border-bottom:solid thin; vertical-align:top; padding:0.2em }
+
+ .warning { color: red; background: transparent; font-weight: bolder; font-style: italic; }
+ .warning p:first-child { margin-top: 0; }
+ .warning p:last-child { margin-bottom: 0; }
+ .warning:before { font-style: normal; }
+ p.warning:before { content: '\26A0 Warning! '; }
+
+ @media print {
+   [data-anolis-spec]::after { content:"[" attr(data-anolis-spec) "]"; font-size:.6em; vertical-align:super; text-transform:uppercase }
+ }
+</style>
+<link rel=stylesheet href="http://www.w3.org/StyleSheets/TR/W3C-[STATUS]">
+<div class=head>
+
+<!-- logo -->
+
+<h1>Web Notifications</h1>
+<h2 class="no-num no-toc">[LONGSTATUS] [DATE: 01 Jan 1901]</h2>
+
+<dl>
+ <dt>This Version:
+ <dd class=dontpublish><a href="http://dvcs.w3.org/hg/notifications/raw-file/tip/Overview.html">http://dvcs.w3.org/hg/notifications/raw-file/tip/Overview.html</a>
+ <dd class=publish><a href="[VERSION]">[VERSION]</a>
+
+ <dt class=publish>Latest Version:
+ <dd class=publish><a href="[LATEST]">[LATEST]</a>
+
+ <dt class=publish>Latest Editors Draft:
+ <dd class=publish><a href="http://dvcs.w3.org/hg/notifications/raw-file/tip/Overview.html">http://dvcs.w3.org/hg/notifications/raw-file/tip/Overview.html</a>
+
+ <dt class=dontpublish>Participate:</dt>
+ <dd class=dontpublish>Send feedback to
+  <a href="mailto:public-web-notification@w3.org">public-web-notification@w3.org</a>
+  (<a href=http://lists.w3.org/Archives/Public/public-web-notification/>archives</a>)
+
+ <dt>Version History:
+ <dd><a href="http://dvcs.w3.org/hg/notifications/shortlog">http://dvcs.w3.org/hg/notifications/shortlog</a></dd>
+
+ <dt>Editor:
+ <dd><a href="http://annevankesteren.nl/">Anne van Kesteren</a>
+ (<a href="http://www.opera.com/">Opera Software ASA</a>)
+ &lt;<a href="mailto:annevk@annevk.nl">annevk@annevk.nl</a>&gt;</dd>
+ <dd>John Gregg (<a href="http://www.google.com/">Google</a>)
+ &lt;<a href="mailto:johnnyg@google.com">johnnyg@google.com</a>>
+</dl>
+
+<!-- copyright -->
+
+</div>
+
+<hr>
+
+<h2 class="no-num no-toc">Abstract</h2>
+
+<p>This document defines an API for displaying simple notifications to the user.
+
+<h2 class="no-num no-toc" id="sotd">Status of this document</h2>
+
+<p>This document is an Editor's Draft and is not suitable for purposes other than reviewing the specification being developed.
+
+<h2 class="no-num no-toc">Table of contents</h2>
+
+<!-- toc -->
+
+
+<h2>Introduction</h2>
+
+<p>This specification provides an API to display notifications to alert
+users outside the context of a web page. It does not specify exactly how a
+user agent should display these notifications; the best presentation depends
+on the device where the user agent is run. When this specification refers
+to displaying notifications on the "desktop", it generally refers to some
+static display area outside the web page, but may take several forms,
+including:
+
+<ul>
+ <li>A corner of the user's display.
+ <li>An area within the chrome of the user agent.
+ <li>The "home" screen of a mobile device.
+</ul>
+
+<p>This specification does not define exactly how the user agent should
+display the notification, and the API is designed to be flexible with
+respect to presentation options.
+
+<p>This specification is designed to be compatible with existing
+notification platforms as much as possible, but also to be
+platform-independent. Since the common platforms do not provide the same
+functionality, this spec will indicate what events are guaranteed and
+which are not. In particular, notifications as specified here only can
+contain text and icon content. In the future, notifications generated from
+web content may wish to contain web content themselves, but that is outside
+the scope of this document.
+
+<p>In general, the event model for notifications is best-effort; while the
+<code>Notification</code> object offers a <code title>click</code> event,
+applications may enhance their functionality by listening for that event,
+but <em>must not depend on receiving it</em>, in case the underlying
+notification platform does not provide that capability.
+
+
+<h2>Conformance</h2>
+
+<p>All diagrams, examples, and notes in this specification are
+non-normative, as are all sections explicitly marked non-normative.
+Everything else in this specification is normative.
+
+<p>The key words "MUST", "MUST NOT", "REQUIRED", <!--"SHALL", "SHALL
+NOT",--> "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
+"OPTIONAL" in the normative parts of this specification are to be
+interpreted as described in RFC2119. For readability, these words do
+not appear in all uppercase letters in this specification.
+<span data-anolis-ref>RFC2119</span>
+
+
+
+<h3>Security</h3>
+
+<p>Notifications should only be presented when the user has indicated they
+are desired; without this they could create a negative experience for the
+user.
+
+
+<h2>Terminology</h2>
+
+<p>Most terminology used in this specification is from DOM and HTML.
+<span data-anolis-ref>DOM</span>
+<span data-anolis-ref>HTML</span>
+
+
+
+<h2>Model</h2>
+
+<p>A <dfn title=concept-notification>notification</dfn> allows alerting the
+user outside a the context of a web page of an occurrence, such as the
+delivery of email.
+
+<p>Each <span title=concept-notification>notification</span> has a
+<dfn>title</dfn>. For specification simplicity each
+<span title=concept-notification>notification</span> also has a
+<dfn>title direction</dfn> and <dfn>body direction</dfn>, both of which are
+initially "<code title>auto</code>".
+
+<p>Each <span title=concept-notification>notification</span> <em>can</em>
+have an associated <dfn>body</dfn>, <dfn>tag</dfn>, and <dfn>icon URL</dfn>.
+
+
+<h3>Permission</h3>
+
+<p><span title=concept-notification>Notifications</span> can only be
+displayed if the user (or user agent on behalf of the user) has granted
+<dfn>permission</dfn>. The <span>permission</span> to display
+<span title=concept-notification>notifications</span> for a given
+<span data-anolis-spec=origin>origin</span> can be one of three strings:
+
+<dl>
+ <dt>"<code title>default</code>"
+ <dd><p>This is equivalent to "<code title>denied</code>", but the user has
+ made no explicit choice thus far.
+
+ <dt>"<code title>denied</code>"
+ <dd><p>This means the user does not want
+ <span title=concept-notification>notifications</span>.
+
+ <dt>"<code title>granted</code>"
+ <dd><p>This means <span title=concept-notification>notifications</span> can
+ be displayed.
+</dl>
+
+<p class=note>The conceptual "<code title>default</code>", but meaning
+"<code title>granted</code>" does not exist. In that case
+"<code title>granted</code>" is simply returned as there would be no reason
+for the application to ask for <span>permission</span>.
+
+
+<h3>Notification lists</h3>
+
+<p>The user agent must keep a <dfn>list of pending notifications</dfn> and
+a <dfn>list of active notifications</dfn>.
+
+<h3>Showing a notification</h3>
+
+<p>The <dfn>show steps</dfn> for a given <var title>notification</var> are:
+
+<ol>
+ <li><p>If notifications are not allowed, cancel any ongoing
+ <span data-anolis-spec=html>fetch</span> for
+ <var title>notification</var>'s <span>icon URL</span>,
+ <span data-anolis-spec=html>queue a task</span> to
+ <span data-anolis-spec=dom title=concept-event-fire>fire an event</span> named
+ <code title>error</code> on <var title>notification</var>, and terminate
+ these steps.
+
+ <li><p>If there is a <span title=concept-notification>notification</span>
+ in the <span>list of pending notifications</span> or the
+ <span>list of active notifications</span> whose <span>tag</span> equals
+ <var title>notification</var>'s <span>tag</span>, run the
+ <span>replace steps</span> and terminate these steps.
+
+ <li><p>If the device allows notifications to be displayed immediately
+ without limitations on the number of concurrent notifications, run
+ the <span>display steps</span> and terminate these steps.
+
+ <li><p>If the device has limitations on the number of concurrent
+ notifications, either immediately call to a notifications platform which
+ natively supports queueing, or append <var title>notification</var> to the
+ <span>list of pending notifications</span>.
+</ol>
+
+<h3>Closing a notification</h3>
+
+<p>When a <span title=concept-notification>notification</span> is closed,
+either by the underlying notifications platform or by the user, the
+<span>close steps</span> must be run.
+
+<p>The <span>close steps</span> are:
+
+<ol>
+ <li><p>If <span title=concept-notification>notification</span> is neither
+ in the <span>list of pending notifications</span> nor in the
+ <span>list of active notifications</span>, terminate these steps.
+
+ <li><p><span data-anolis-spec=html>Queue a task</span> to remove
+ <span title=concept-notification>notification</span> from either the
+ <span>list of pending notifications</span> or the
+ <span>list of active notifications</span>, and
+ <span data-anolis-spec=dom title=concept-event-fire>fire an event</span>
+ named <code title>close</code> on
+ <span title=concept-notification>notification</span>.
+</ol>
+
+<h3>Pending notifications</h3>
+
+<p>Whenever the <span>list of pending notifications</span> is not empty, the
+user agent must wait and monitor changes in the available notification space
+on the device.
+
+<p>When the available display space changes on the device such that a new
+notification can be displayed, for example due to a previous notification
+being dismissed, the user agent should run the <span>display steps</span>
+for the first <span title=concept-notification>notification</span> in the
+<span>list of pending notifications</span> and then remove it from the
+<span>list of pending notifications</span>.
+
+<h3>Displaying notifications</h3>
+
+<p>The <dfn>display steps</dfn> for a given <var title>notification</var>
+are:
+
+<ol>
+ <li><p>If the notification platform supports icons and
+ <var title>notification</var>'s <span>icon URL</span> has not yet been
+ <span data-anolis-spec=html title=fetch>fetched</span>,
+ <span data-anolis-spec=html>fetch</span> it and wait for the resource to be
+ fully downloaded.
+
+ <li><p>If <span data-anolis-spec=html title=fetch>fetching</span>
+ <var title>notification</var>'s <span>icon URL</span> failed for some
+ reason or the image format is not supported,
+ <span data-anolis-spec=html>queue a task</span> to
+ <span data-anolis-spec=dom title=concept-event-fire>fire an event</span>
+ named <code title>error</code> on <var title>notification</var> and terminate
+ these steps.
+
+ <li><p><span data-anolis-spec=html>Queue a task</span> to display
+ <var title>notification</var> on the device (e.g. by calling the
+ appropriate notification platform), append <var title>notification</var> to the
+ <span>list of active notifications</span>, and
+ <span data-anolis-spec=dom title=concept-event-fire>fire an event</span>
+ named <code title>show</code> on <var title>notification</var>.
+</ol>
+
+
+<h3>Replacing a notification</h3>
+
+<p>The <dfn>replace steps</dfn> for replacing an <var title>old</var>
+<span title=concept-notification>notification</span> with a
+<var title>new</var> one are:
+
+<ol>
+ <li><p>If the notification platform supports icons and
+ <var title>new</var>'s <span>icon URL</span> has not yet been
+ <span data-anolis-spec=html title=fetch>fetched</span>,
+ <span data-anolis-spec=html>fetch</span> it and wait for the resource to be
+ fully downloaded.
+
+ <li><p>If <span data-anolis-spec=html title=fetch>fetching</span>
+ <var title>new</var>'s <span>icon URL</span> failed for some
+ reason or the image format is not supported,
+ <span data-anolis-spec=html>queue a task</span> to
+ <span data-anolis-spec=dom title=concept-event-fire>fire an event</span>
+ named <code title>error</code> on <var title>new</var> and terminate
+ these steps.
+
+ <li><p>If <var title>old</var> is in the
+ <span>list of pending notifications</span>,
+ <span data-anolis-spec=html>queue a task</span> to replace
+ <var title>old</var> with <var title>new</var>, in the same position, in
+ the <span>list of pending notifications</span>, and
+ <span data-anolis-spec=dom title=concept-event-fire>fire an event</span>
+ named <code title>close</code> on <var title>old</var>.
+
+ <li>
+  <p>Otherwise,
+  <span data-anolis-spec=html>queue a task</span> to replace
+  <var title>old</var> with <var title>new</var>, in the same position, in
+  the <span>list of active notifications</span>,
+  <span data-anolis-spec=dom title=concept-event-fire>fire an event</span>
+  named <code title>close</code> on <var title>old</var>, and
+  <span data-anolis-spec=dom title=concept-event-fire>fire an event</span>
+  named <code title>show</code> on <var title>new</var>.
+
+  <p>If the notification platform does not support replacement this
+  requirement may be addressed by removal and addition instead.
+</ol>
+
+
+
+<h2>API</h2>
+
+<p>A <span title=concept-notification>notification</span> is represented by
+a <code>Notification</code> object and can be created by its
+<span title=dom-Notification>constructor</span>.
+
+<pre class="idl">[<span title=dom-Notification>Constructor</span>(DOMString <var title>title</var>, optional <span>NotificationOptions</span> <var title>options</var>)]
+interface <dfn>Notification</dfn> : <span data-anolis-spec=dom>EventTarget</span> {
+  static readonly attribute <span>NotificationPermission</span> <span title=dom-Notification-permission>permission</span>;
+  static void <span title=dom-Notification-requestPermission>requestPermission</span>(<span>NotificationPermissionCallback</span> <var title>callback</var>);
+
+  [TreatNonCallableAsNull] attribute <span data-anolis-spec=html>Function</span>? <span title=handler-onclick>onclick</span>;
+  [TreatNonCallableAsNull] attribute <span data-anolis-spec=html>Function</span>? <span title=handler-onshow>onshow</span>;
+  [TreatNonCallableAsNull] attribute <span data-anolis-spec=html>Function</span>? <span title=handler-onerror>onerror</span>;
+  [TreatNonCallableAsNull] attribute <span data-anolis-spec=html>Function</span>? <span title=handler-onclose>onclose</span>;
+
+  void <span title=dom-Notification-close>close</span>();
+};
+
+dictionary <dfn>NotificationOptions</dfn> {
+  <span>NotificationDirection</span> titleDir;
+  DOMString body;
+  <span>NotificationDirection</span> bodyDir;
+  DOMString tag;
+  DOMString iconUrl;
+};
+
+enum <dfn>NotificationPermission</dfn> {
+  "default",
+  "denied",
+  "granted"
+};
+
+callback <dfn>NotificationPermissionCallback</dfn> = void (<span>NotificationPermission</span> <var title>permission</var>);
+
+enum <dfn>NotificationDirection</dfn> {
+  "auto",
+  "ltr",
+  "rtl"
+};</pre>
+
+<p>The
+<dfn title=dom-Notification><code>Notification(<var title>title</var>, <var title>options</var>)</code></dfn>
+constructor must run these steps:
+
+<ol>
+ <li><p>Let <var title>notification</var> be a new
+ <span title=concept-notification>notification</span> represented by a
+ <code>Notification</code> object.
+
+ <li><p>Set <var title>notification</var>'s <span>title</span> to
+ <var title>title</var>,
+ <span data-anolis-spec=webidl title="convert a DOMString to a sequence of Unicode characters">converted to Unicode</span>.
+
+ <li><p>If <var title>options</var> is not omitted and its
+ <code title>titleDir</code> member is not null, set
+ <var title>notification</var>'s <span>title direction</span> to
+ <code title>titleDir</code>.
+
+ <li><p>If <var title>options</var> is not omitted and its
+ <code title>body</code> is not null, set <var title>notification</var>'s
+ <span>body</span> to <code title>body</code>,
+ <span data-anolis-spec=webidl title="convert a DOMString to a sequence of Unicode characters">converted to Unicode</span>.
+
+ <li><p>If <var title>options</var> is not omitted and its
+ <code title>bodyDir</code> member is not null, set
+ <var title>notification</var>'s <span>body direction</span> to
+ <code title>bodyDir</code>.
+
+ <li><p>If <var title>options</var> is not omitted and its
+ <code title>tag</code> is not null, set <var title>notification</var>'s
+ <span>tag</span> to <code title>tag</code>.
+
+ <li><p>If <var title>options</var> is not omitted and its
+ <code title>iconUrl</code> is not null, set <var title>notification</var>'s
+ <span>icon URL</span> to <code title>iconUrl</code>.
+
+ <li><p>Return <var title>notification</var>, but continue running these
+ steps asynchronouusly.
+
+ <li><p>If the notification platform supports icons, the user agent may
+ start <span data-anolis-spec=html title=fetch>fetching</span>
+ <var title>notification</var>'s <span>icon URL</span> at this point.
+
+ <li><p>Run the <span>show steps</span> for <var title>notification</var>.
+</ol>
+
+<p>The static
+<dfn title=dom-Notification-permission><code>permission</code></dfn>
+attribute must return <span>permission</span>.
+
+<p>The static
+<dfn title=dom-Notification-requestPermission><code>requestPermission(<var title>callback</var>)</code></dfn>
+method must run these steps:
+
+<ol>
+ <li><p>Return, but continue running these steps asynchronously.
+
+ <li><p>Let <var title>permission</var> be <span>permission</span>.
+
+ <li><p>If <var title>permission</var> is "<code title>default</code>",
+ ask the user whether showing notifications for the current
+ <span data-anolis-spec=origin>origin</span> is acceptable. If it is, set
+ <var title>permission</var> to "<code title>granted</code>", or
+ "<code title>denied</code>" otherwise.
+
+ <li><p><span data-anolis-spec=html>Queue a task</span> to set
+ <code title=dom-Notification-permission>permission</code> to
+ <var title>permission</var> and invoke <var title>callback</var> with
+ <var title>permission</var> as single argument.
+</ol>
+
+<p>The following are the <span data-anolis-spec=html>event handlers</span>
+(and their corresponding
+<span data-anolis-spec=html title="event handler event type">event handler event types</span>)
+that must be supported as attributes by the <code>Notification</code> object.
+
+<table>
+ <thead>
+  <tr>
+   <th><span data-anolis-spec=html title="event handlers">event handler</span>
+   <th><span data-anolis-spec=html>event handler event type</span>
+ <tbody>
+  <tr>
+   <td><dfn title=handler-onclick><code>onclick</code></dfn>
+   <td><code title=event-click>click</code>
+  <tr>
+   <td><dfn title=handler-onshow><code>onshow</code></dfn>
+   <td><code title=event-show>show</code>
+  <tr>
+   <td><dfn title=handler-onerror><code>onerror</code></dfn>
+   <td><code title=event-error>error</code>
+  <tr>
+   <td><dfn title=handler-onclose><code>onclose</code></dfn>
+   <td><code title=event-close>close</code>
+</table>
+
+<p>The <dfn title=dom-Notification-close><code>close()</code></dfn> method
+must run the <span>close steps</span> for the
+<span title=concept-notification>notification</span>.
+
+
+
+
+
+<h2>Rendering</h2>
+
+<p class=XXX>bidi
+
+
+<h2>Examples</h2>
+
+<h3>Using events</h3>
+
+<p>
+	Notification objects dispatch events during their lifecycle, which authors can use
+	to generate desired behaviors.
+      </p>
+      <p>
+	The <code>show</code> event occurs when the notification is shown to the user --
+	this may be at some time after the notification is created in the case
+	of limited display space and a queue.
+      </p>
+
+      <p>
+	In the following example, this event is used to guarantee that regardless of when
+	the notification is shown, it is displayed for only 15 seconds.
+      </p>
+
+<pre class="example">new Notification("New Email Received",
+                 { iconUrl: "mail.png",
+                   onshow: function() { setTimeout(notification.close(), 15000); }
+                 });</pre>
+
+<p>The <code>close</code> events occurs when the notification is dismissed by the user.
+	Authors may use this event to perform actions when notifications are acknowledged.
+
+<p>
+	In the following example, when a meeting reminder notification is acknowledged, the
+	application suppresses other forms of reminders.
+      </p>
+
+<pre class="example">new Notification("Meeting about to begin",
+                 { iconUrl: "calendar.gif",
+                   body: "Room 101",
+                   onclose: function() { cancelReminders(event); }
+                 });</pre>
+
+
+<h3 id="tags-example">Using the tag attribute for multiple instances</h3>
+
+<p>Web applications frequently operate concurrently in multiple instances, such as when a
+	user opens a mail application in multiple browser tabs.  Since the desktop is a shared
+	resource, Web Notifications provides a way for these instances to easily coordinate, by
+	using the <code>tag</code> attribute.
+
+<p>Notifications which represent the same conceptual event can be tagged in the same way,
+	and when both are shown, the user will only receive one notification.
+      </p>
+
+<pre class="example" title="">Instance 1                                   | Instance 2
+                                             |
+// Instance notices there is new mail.       |
+new Notification("New mail from John Doe",   |
+                 { tag: 'message1' });       |
+                                             |
+                                             |  // Slightly later, this instance notices
+                                             |  // there is new mail.
+                                             |  new Notification("New mail from John Doe",
+                                             |                   { tag: 'message1' });</pre>
+
+<p>
+	The result of this situation, if the user agent follows the algorithms here, is a <strong>single</strong> notification "New mail from John Doe".
+
+<h3>Using the tag attribute for a single instance</h3>
+
+<p>The tag attribute can also be used by a single instance of an application to keep its
+	notifications as current as possible as state changes.
+
+<p>For example, if Alice is using a chat application with Bob, and Bob sends multiple
+	messages while Alice is idle, the application may prefer that Alice not see a
+	desktop notification for each message.
+
+<pre class="example">// Bob says "Hi"
+new Notification("Bob: Hi", { tag: 'chat_Bob' });
+
+// Bob says "Are you free this afternoon?"
+new Notification("Bob: Hi / Are you free this afternoon?", { tag: 'chat_Bob' });</pre>
+
+<p>The result of this situation is a <em>single</em> notification; the second one
+	replaces the first having the same tag.  In a platform that queues notifications
+	(first-in-first-out), using the tag allows the notification to also maintain its
+	position in the queue.  Platforms where the newest notifications are shown first,
+	a similar result could be achieved using the
+	<code title=dom-Notification-close>close()</code> method.
+
+<h2 class=no-num>References</h2>
+
+<div id=anolis-references></div>
+
+<h2 class=no-num>Acknowledgments</h2>
+
+<p>Thanks to
+Alex Russell,
+Doug Turner,
+Drew Wilson,
+Edward O'Connor,
+Ian Hickson,
+James Graham,
+Jon Lee, and
+Jonas Sicking
+for being awesome.