You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bu...@apache.org on 2011/02/08 01:01:12 UTC

svn commit: r784964 - in /websites/staging/trafficserver/trunk/content/docs/trunk: ./ sdk/actions-guide/ sdk/continuations/ sdk/plugin-configurations/

Author: buildbot
Date: Tue Feb  8 00:01:11 2011
New Revision: 784964

Log:
Staging update by buildbot

Modified:
    websites/staging/trafficserver/trunk/content/docs/trunk/STATUS
    websites/staging/trafficserver/trunk/content/docs/trunk/sdk/actions-guide/hosts-lookup-api.en.html
    websites/staging/trafficserver/trunk/content/docs/trunk/sdk/actions-guide/index.en.html
    websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/how-to-activate-continuations.en.html
    websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/index.en.html
    websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/writing-handler-functions.en.html
    websites/staging/trafficserver/trunk/content/docs/trunk/sdk/plugin-configurations/index.en.html

Modified: websites/staging/trafficserver/trunk/content/docs/trunk/STATUS
==============================================================================
--- websites/staging/trafficserver/trunk/content/docs/trunk/STATUS (original)
+++ websites/staging/trafficserver/trunk/content/docs/trunk/STATUS Tue Feb  8 00:01:11 2011
@@ -61,8 +61,8 @@ http-hooks-and-transactions -- igalic
 misc-interface-guide -- igalic
 http-headers  -- igalic
 mutex-guide  -- igalic
-continuations
-plugin-configurations
+continuations -- igalic
+plugin-configurations -- igalic
 actions-guide
 io-guide
 plugin-management

Modified: websites/staging/trafficserver/trunk/content/docs/trunk/sdk/actions-guide/hosts-lookup-api.en.html
==============================================================================
--- websites/staging/trafficserver/trunk/content/docs/trunk/sdk/actions-guide/hosts-lookup-api.en.html (original)
+++ websites/staging/trafficserver/trunk/content/docs/trunk/sdk/actions-guide/hosts-lookup-api.en.html Tue Feb  8 00:01:11 2011
@@ -6,8 +6,8 @@
     
     <link rel="stylesheet" href="/styles/pygments_style.css" />
     
-    <title></title>
-    
+    <title>Apache Traffic Server™ Software Developers Kit</title>
+    <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file to you under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with the License.  You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License. -->
   </head>
 
   <body>
@@ -15,11 +15,20 @@
 	    <span id="ts_logo">
 		  <a href="http://trafficserver.apache.org/"><img alt="Apache Traffic Server" src="/images/ts75.png" /></a>
 	  </span>
-	    <h1></h1>
+	    <h1>Apache Traffic Server™ Software Developers Kit</h1>
     </div>
 
   <div id="content">
-      
+      <p><a href="../actions-guide">Prev</a> - Actions Guide</p>
+<p>IO Guide - <a href="../io-guide">Next</a></p>
+<h2 id="HostsLookupAPI">Hosts Lookup API</h2>
+<p>The hosts lookup enables plugins to ask Traffic Server to do a host lookup 
+of a host name, much like a DNS lookup.</p>
+<p>The hosts lookup functions are as follows:</p>
+<ul>
+<li><a href="link/to/doxygen"><code>TSHostLookup</code></a></li>
+<li><a href="link/to/doxygen"><code>TSHostLookupResultIPGet</code></a></li>
+</ul>
   </div>
 
   <div id="footer">

Modified: websites/staging/trafficserver/trunk/content/docs/trunk/sdk/actions-guide/index.en.html
==============================================================================
--- websites/staging/trafficserver/trunk/content/docs/trunk/sdk/actions-guide/index.en.html (original)
+++ websites/staging/trafficserver/trunk/content/docs/trunk/sdk/actions-guide/index.en.html Tue Feb  8 00:01:11 2011
@@ -6,8 +6,8 @@
     
     <link rel="stylesheet" href="/styles/pygments_style.css" />
     
-    <title></title>
-    
+    <title>Apache Traffic Server™ Software Developers Kit</title>
+    <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file to you under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with the License.  You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations -->
   </head>
 
   <body>
@@ -15,11 +15,159 @@
 	    <span id="ts_logo">
 		  <a href="http://trafficserver.apache.org/"><img alt="Apache Traffic Server" src="/images/ts75.png" /></a>
 	  </span>
-	    <h1></h1>
+	    <h1>Apache Traffic Server™ Software Developers Kit</h1>
     </div>
 
   <div id="content">
-      
+      <p><a href="../plugin-configurations">Prev</a> - Plugin Configurations</p>
+<p>Hosts Lookup API - <a href="hosts-lookup-api">Next</a></p>
+<h2 id="ActionsGuide">Actions Guide</h2>
+<p><strong>Table of Contents</strong></p>
+<ul>
+<li><a href="#Actions">Actions</a></li>
+<li><a href="hosts-lookup-api">Hosts Lookup API</a></li>
+</ul>
+<h2 id="Actions">Actions</h2>
+<p>An <strong>action</strong> is a handle to an operation initiated by a plugin that has not 
+yet completed. For example: when a plugin connects to a remote server, it uses 
+the call <code>TSNetConnect</code> - which takes <code>TSCont</code> as an argument to call back 
+when the connection is established. <code>TSNetConnect</code> might not call the continuation 
+back immediately and will return an <code>TSAction</code> structure that the caller can 
+use to cancel the operation. Cancelling the operation does not necessarily 
+mean that the operation will not occur; it simply means that the continuation 
+passed into the operation will not be called back. In such an example, the 
+connection might still occur if the action is cancelled; however, the continuation 
+that initiated the connection would not be called back.</p>
+<p>In the preceding example, it is also possible that the connection will complete 
+and call back the continuation before <code>TSNetConnect</code> returns. If that occurs, 
+then <code>TSNetConnect</code> returns a special action that causes <code>TSActionDone</code> to 
+return <code>1</code>. This specifies that the operation has already completed, so it's 
+pointless to try to cancel the operation. Also note that an action will never 
+change from non-completed to completed. When the operation actually succeeds 
+and the continuation is called back, the continuation must zero out its action 
+pointer to indicate to itself that the operation succeeded.</p>
+<p>The asynchronous nature of all operations in Traffic Server necessitates actions. 
+You should notice from the above discussion that once a call to a function 
+like <code>TSNetConnect</code> is made by a continuation and that function returns a 
+valid action (<code>TSActionDone</code> returns <code>0</code>), it is not safe for the continuation 
+to do anything else except return from its handler function. It is not safe 
+to modify or examine the continuation's data because the continuation may have 
+already been destroyed.</p>
+<p>Below is an example of typical usage for an action:</p>
+<div class="codehilite"><pre><span class="cp">    #include &lt;ts/ts.h&gt;</span>
+    <span class="k">static</span> <span class="kt">int</span>
+    <span class="nf">handler</span> <span class="p">(</span><span class="n">TSCont</span> <span class="n">contp</span><span class="p">,</span> <span class="n">TSEvent</span> <span class="n">event</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">edata</span><span class="p">)</span>
+    <span class="p">{</span>
+        <span class="k">if</span> <span class="p">(</span><span class="n">event</span> <span class="o">==</span> <span class="n">TS_EVENT_IMMEDIATE</span><span class="p">)</span> <span class="p">{</span>
+            <span class="n">TSAction</span> <span class="n">actionp</span> <span class="o">=</span> <span class="n">TSNetConnect</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="mf">127.0.0.1</span><span class="p">,</span> <span class="mi">9999</span><span class="p">);</span>
+            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">TSActionDone</span> <span class="p">(</span><span class="n">actionp</span><span class="p">))</span> <span class="p">{</span>
+                <span class="n">TSContDataSet</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="n">actionp</span><span class="p">);</span>
+            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
+                <span class="cm">/* We&#39;ve already been called back... */</span>
+                <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
+            <span class="p">}</span>
+        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">event</span> <span class="o">==</span> <span class="n">TS_EVENT_NET_CONNECT</span><span class="p">)</span> <span class="p">{</span>
+            <span class="cm">/* Net connection succeeded */</span>
+            <span class="n">TSContDataSet</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
+            <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
+        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">event</span> <span class="o">==</span> <span class="n">TS_EVENT_NET_CONNECT_FAILED</span><span class="p">)</span> <span class="p">{</span>
+            <span class="cm">/* Net connection failed */</span>
+            <span class="n">TSContDataSet</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
+            <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
+        <span class="p">}</span> 
+        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
+    <span class="p">}</span>
+
+    <span class="kt">void</span>
+    <span class="nf">TSPluginInit</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
+    <span class="p">{</span>
+        <span class="n">TSCont</span> <span class="n">contp</span><span class="p">;</span>
+
+        <span class="n">contp</span> <span class="o">=</span> <span class="n">TSContCreate</span> <span class="p">(</span><span class="n">handler</span><span class="p">,</span> <span class="n">TSMutexCreate</span> <span class="p">());</span>
+
+        <span class="cm">/* We don&#39;t want to call things out of TSPluginInit</span>
+<span class="cm">           directly since it&#39;s called before the rest of the</span>
+<span class="cm">           system is initialized. We&#39;ll simply schedule an event</span>
+<span class="cm">           on the continuation to occur as soon as the rest of</span>
+<span class="cm">           the system is started up. */</span>
+        <span class="n">TSContSchedule</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
+    <span class="p">}</span>
+</pre></div>
+
+
+<p>The example above shows a simple plugin that creates a continuation and then 
+schedules it to be called immediately. When the plugin's handler function is 
+called the first time, the event is <code>TS_EVENT_IMMEDIATE</code>. The plugin then 
+tries to open a net connection to port 9999 on <code>localhost</code> (127.0.0.1). The 
+IP description was left in cider notation to further clarify what is going 
+on; also note that the above won't actually compile until the IP address is 
+modified. The action returned from <code>TSNetConnect</code> is examined by the plugin. 
+If the operation has not completed, then the plugin stores the action in its 
+continuation. Otherwise, the plugin knows it has already been called back and 
+there is no reason to store the action pointer.</p>
+<p>A final question might be, "why would a plugin want to cancel an action?" In 
+the above example, a valid reason could be to place a limit on the length of 
+time it takes to open a connection. The plugin could schedule itself to get 
+called back in 30 seconds and then initiate the net connection. If the timeout 
+expires first, then the plugin would cancel the action. The following sample 
+code implements this:</p>
+<div class="codehilite"><pre><span class="cp">    #include &lt;ts/ts.h&gt;</span>
+    <span class="k">static</span> <span class="kt">int</span>
+    <span class="nf">handler</span> <span class="p">(</span><span class="n">TSCont</span> <span class="n">contp</span><span class="p">,</span> <span class="n">TSEvent</span> <span class="n">event</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">edata</span><span class="p">)</span>
+    <span class="p">{</span>
+        <span class="k">switch</span> <span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="p">{</span>
+            <span class="k">case</span> <span class="p">(</span><span class="n">TS_EVENT_IMMEDIATE</span><span class="p">)</span>:
+                <span class="n">TSContSchedule</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="mi">30000</span><span class="p">);</span>
+                <span class="n">TSAction</span> <span class="n">actionp</span> <span class="o">=</span> <span class="n">TSNetConnect</span><span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="mf">127.0.0.1</span><span class="p">,</span> <span class="mi">9999</span><span class="p">);</span>
+                <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">TSActionDone</span> <span class="p">(</span><span class="n">actionp</span><span class="p">))</span> <span class="p">{</span>
+                    <span class="n">TSContDataSet</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="n">actionp</span><span class="p">);</span>
+                <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
+                    <span class="cm">/* We&#39;ve already been called back ... */</span>
+                <span class="p">}</span>
+                <span class="k">break</span><span class="p">;</span>
+
+            <span class="k">case</span> <span class="p">(</span><span class="n">TS_EVENT_TIMEOUT</span><span class="p">)</span>:
+                <span class="n">TSAction</span> <span class="n">actionp</span> <span class="o">=</span> <span class="n">TSContDataGet</span> <span class="p">(</span><span class="n">contp</span><span class="p">);</span>
+                <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">TSActionDone</span><span class="p">(</span><span class="n">actionp</span><span class="p">))</span> <span class="p">{</span>
+                    <span class="n">TSActionCancel</span> <span class="p">(</span><span class="n">actionp</span><span class="p">);</span>
+                <span class="p">}</span>
+                <span class="k">break</span><span class="p">;</span>
+
+            <span class="k">case</span> <span class="p">(</span><span class="n">TS_EVENT_NET_CONNECT</span><span class="p">)</span>:
+                <span class="cm">/* Net connection succeeded */</span>
+                <span class="n">TSContDataSet</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
+                <span class="k">break</span><span class="p">;</span>
+
+            <span class="k">case</span> <span class="p">(</span><span class="n">TS_EVENT_NET_CONNECT_FAILED</span><span class="p">)</span>:
+                <span class="cm">/* Net connection failed */</span>
+                <span class="n">TSContDataSet</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
+                <span class="k">break</span><span class="p">;</span>
+
+        <span class="p">}</span> 
+        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
+    <span class="p">}</span>
+
+    <span class="kt">void</span>
+    <span class="nf">TSPluginInit</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
+    <span class="p">{</span>
+        <span class="n">TSCont</span> <span class="n">contp</span><span class="p">;</span>
+
+        <span class="n">contp</span> <span class="o">=</span> <span class="n">TSContCreate</span> <span class="p">(</span><span class="n">handler</span><span class="p">,</span> <span class="n">TSMutexCreate</span> <span class="p">());</span>
+        <span class="cm">/* We don&#39;t want to call things out of TSPluginInit</span>
+<span class="cm">           directly since it&#39;s called before the rest of the</span>
+<span class="cm">           system is initialized. We&#39;ll simply schedule an event</span>
+<span class="cm">           on the continuation to occur as soon as the rest of</span>
+<span class="cm">           the system is started up. */</span>
+        <span class="n">TSContSchedule</span> <span class="p">(</span><span class="n">contp</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
+    <span class="p">}</span>
+</pre></div>
+
+
+<p>The action functions are:</p>
+<ul>
+<li><a href="link/to/doxygen"><code>TSActionCancel</code></a></li>
+<li><a href="link/to/doxygen"><code>TSActionDone</code></a></li>
+</ul>
   </div>
 
   <div id="footer">

Modified: websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/how-to-activate-continuations.en.html
==============================================================================
--- websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/how-to-activate-continuations.en.html (original)
+++ websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/how-to-activate-continuations.en.html Tue Feb  8 00:01:11 2011
@@ -6,8 +6,8 @@
     
     <link rel="stylesheet" href="/styles/pygments_style.css" />
     
-    <title></title>
-    
+    <title>Apache Traffic Server™ Software Developers Kit</title>
+    <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file to you under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with the License.  You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License. -->
   </head>
 
   <body>
@@ -15,11 +15,31 @@
 	    <span id="ts_logo">
 		  <a href="http://trafficserver.apache.org/"><img alt="Apache Traffic Server" src="/images/ts75.png" /></a>
 	  </span>
-	    <h1></h1>
+	    <h1>Apache Traffic Server™ Software Developers Kit</h1>
     </div>
 
   <div id="content">
-      
+      <p><a href="../continuations">Prev</a> - Continuations</p>
+<p>Writing Handler Functions - <a href="writing-handler-functions">Next</a></p>
+<h2 id="HowActivateContinuations">How to Activate Continuations</h2>
+<p>Continuations are activated when they receive an event or by <code>TSContSchedule</code> 
+(which schedules a continuation to receive an event). Continuations might receive 
+an event because:</p>
+<ul>
+<li>
+<p>Your plugin calls <code>TSContCall</code></p>
+</li>
+<li>
+<p>The Traffic Server HTTP state machine sends an event corresponding to a particular 
+HTTP hook</p>
+</li>
+<li>
+<p>A Traffic Server IO processor (such as a cache processor or net processor) 
+is letting a continuation know there is data (cache or network) available to 
+read or write. These callbacks are a result of using functions such <code>TSVConnRead</code>/<code>Write</code> 
+or <code>TSCacheRead</code>/<code>Write</code></p>
+</li>
+</ul>
   </div>
 
   <div id="footer">

Modified: websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/index.en.html
==============================================================================
--- websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/index.en.html (original)
+++ websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/index.en.html Tue Feb  8 00:01:11 2011
@@ -6,8 +6,8 @@
     
     <link rel="stylesheet" href="/styles/pygments_style.css" />
     
-    <title></title>
-    
+    <title>Apache Traffic Server™ Software Developers Kit</title>
+    <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file to you under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with the License.  You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License. -->
   </head>
 
   <body>
@@ -15,11 +15,116 @@
 	    <span id="ts_logo">
 		  <a href="http://trafficserver.apache.org/"><img alt="Apache Traffic Server" src="/images/ts75.png" /></a>
 	  </span>
-	    <h1></h1>
+	    <h1>Apache Traffic Server™ Software Developers Kit</h1>
     </div>
 
   <div id="content">
-      
+      <p><a href="../mutex-guide">Prev</a> - Mutex Guide</p>
+<p>How to Activate Continuations - <a href="how-to-activate-continuations">Next</a></p>
+<h2 id="Continuations">Continuations</h2>
+<p><strong>Table of Contents</strong></p>
+<p><a href="#MutexesData">Mutexes and Data</a>
+<a href="how-to-activate-continuations">How to Activate Continuations</a>
+<a href="writing-handler-functions">Writing Handler Functions</a></p>
+<p>The continuation interface is Traffic Server's basic callback mechanism. <strong>Continuations</strong> 
+are instances of the opaque data type <code>TSCont</code>. In its basic form, a continuation 
+represents a handler function and a mutex. </p>
+<p>This chapter covers the following topics:</p>
+<ul>
+<li>
+<p><a href="MutexesData">Mutexes and Data</a></p>
+</li>
+<li>
+<p><a href="ActivateContinuations.html">How to Activate Continuations</a></p>
+</li>
+<li>
+<p><a href="WritingHandlerFunctions.html">Writing Handler Functions</a></p>
+</li>
+</ul>
+<h2 id="MutexesData">Mutexes and Data</h2>
+<p>A continuation must be created with a mutex if your continuation does one of 
+the following:</p>
+<ul>
+<li>
+<p>is registered globally (<code>TSHttpHookAdd</code> or <code>TSHttpSsnHookAdd</code>) to an HTTP 
+hook and uses <code>TSContDataSet/Get</code></p>
+</li>
+<li>
+<p>is registered locally (<code>TSHttpTxnHookAdd</code>), but for multiple transactions 
+uses <code>TSContDataSet/Get</code></p>
+</li>
+<li>
+<p>uses <code>TSCacheXXX</code>, <code>TSNetXXX</code>, <code>TSHostLookup</code>, or <code>TSContSchedule</code> APIs </p>
+</li>
+</ul>
+<p>Before being activated, a caller must grab the continuation's mutex. This requirement 
+makes it possible for a continuation's handler function to safely access its 
+data and to prevent multiple callers from running it at the same time (see 
+the <a href="../new-protocol-plugins#AboutSampleProtocol">sample Protocol plugin</a> for 
+usage). The data protected by the mutex is any global or continuation data 
+associated to the continuation by <code>TSContDataSet</code>. This does not include the 
+local data created by the continuation handler function. A typical example 
+of continuations created with associated data structures and mutexes is the 
+transaction state machine created in the sample Protocol plugin (see <a href="../new-protocol-plugins#OneWayImplementaTransactionStateMachine">One Way 
+to Implement a Transaction State Machine</a>). </p>
+<p>A reentrant call occurs when the continuation passed as an argument to the 
+API can be called in the same stack trace as the function calling the API. 
+For example, if you call <code>TSCacheRead</code> (<code>contp, mykey</code>), it is possible that 
+<code>contp</code>'s handler will be called directly and then <code>TSCacheRead</code> returns. </p>
+<p>Caveats that could cause issues include the following:</p>
+<ul>
+<li>
+<p>a continuation has data associated with it (<code>TSContDataGet</code>).</p>
+</li>
+<li>
+<p>the reentrant call passes itself as a continuation to the reentrant API. In 
+this case, the continuation should not try to access its data after calling 
+the reentrant API. The reason for this is that data may be modified by the 
+section of code in the continuation's handler that handles the event sent by 
+the API. It is recommended that you always return after a reentrant call to 
+avoid accessing something that has been deallocated.</p>
+</li>
+</ul>
+<p>Below is an example, followed by an explanation.</p>
+<div class="codehilite"><pre><span class="n">continuation_handler</span> <span class="p">(</span><span class="n">TSCont</span> <span class="n">contp</span><span class="p">,</span> <span class="n">TSEvent</span> <span class="n">event</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">edata</span><span class="p">)</span> <span class="p">{</span>
+    <span class="k">switch</span> <span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="p">{</span>
+        <span class="k">case</span> <span class="n">event1</span>:
+            <span class="n">TSReentrantCall</span> <span class="p">(</span><span class="n">contp</span><span class="p">);</span>
+            <span class="cm">/* Return right away after this call */</span>
+            <span class="k">break</span><span class="p">;</span>
+        <span class="k">case</span> <span class="n">event2</span>:
+            <span class="n">TSContDestroy</span> <span class="p">(</span><span class="n">contp</span><span class="p">);</span>
+            <span class="k">break</span><span class="p">;</span>
+    <span class="p">}</span>
+<span class="p">}</span>
+</pre></div>
+
+
+<p>The above example first assumes that the continuation is called back with <code>event1</code>; 
+it then does the first reentrant call that schedules the continuation to receive 
+<code>event2</code>. Because the call is reentrant, the processor calls back the continuation 
+right away with <code>event2</code> and the continuation is destroyed. If you try to access 
+the continuation or one of its members after the reentrant call, then you might 
+access something that has been deallocated. To avoid accessing something that 
+has been deallocated, never access the continuation or any of its members after 
+a reentrant call - just exit the handler.</p>
+<p><strong>Note:</strong> Most HTTP transaction plugin continuations do not need non-null mutexes 
+because they're called within the processing of an HTTP transaction, and therefore 
+have the transaction's mutex.</p>
+<p>It is also possible to specify a continuation's mutex as <code>NULL</code>. This should 
+be done only when registering a continuation to a global hook, by a call to 
+<code>TSHttpHookAdd</code>. In this case, the continuation can be called simultaneously 
+by different instances of HTTP SM running on different threads. Having a mutex 
+here would slow and/or hinder Traffic Server performance, since all the threads 
+will try to lock the same mutex. The drawback of not having a mutex is that 
+such a continuation cannot have data associated with it (i.e., <code>TSContDataGet/Set</code> 
+cannot be used).</p>
+<p>When using a <code>NULL</code> mutex it is dangerous to access the continuation's data, 
+but usually continuations with <code>NULL</code> mutexes have no data associated with 
+them anyway. An example of such a continuation is one that gets called back 
+every time an HTTP request is read, and then determines from the request alone 
+if the request should go through or be rejected. An HTTP transaction gives 
+its continuation data to the <code>contp</code>.</p>
   </div>
 
   <div id="footer">

Modified: websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/writing-handler-functions.en.html
==============================================================================
--- websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/writing-handler-functions.en.html (original)
+++ websites/staging/trafficserver/trunk/content/docs/trunk/sdk/continuations/writing-handler-functions.en.html Tue Feb  8 00:01:11 2011
@@ -6,8 +6,8 @@
     
     <link rel="stylesheet" href="/styles/pygments_style.css" />
     
-    <title></title>
-    
+    <title>Apache Traffic Server™ Software Developers Kit</title>
+    <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file to you under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with the License.  You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License. -->
   </head>
 
   <body>
@@ -15,11 +15,248 @@
 	    <span id="ts_logo">
 		  <a href="http://trafficserver.apache.org/"><img alt="Apache Traffic Server" src="/images/ts75.png" /></a>
 	  </span>
-	    <h1></h1>
+	    <h1>Apache Traffic Server™ Software Developers Kit</h1>
     </div>
 
   <div id="content">
-      
+      <p><a href="how-to-activate-continuations">Prev</a> - How to Activate Continuations</p>
+<p>Chapter 13. Plugin Configurations - <a href="../plugin-configurations">Next</a></p>
+<h2 id="WritingHandlerFunctions">Writing Handler Functions</h2>
+<p>The handler function is the key component of a continuation. It is supposed 
+to examine the event and event data, and then do something appropriate. The 
+probable action might be to schedule another event for the continuation to 
+received, to open up a connection to a server, or simply to destroy itself. </p>
+<p>The continuation's handler function is a function of type <code>TSEventFunc</code>. Its 
+arguments are a continuation, an event, and a pointer to some data (this data 
+is passed to the continuation by the caller - do not confuse this data with 
+the continuation's own data, associated by <code>TSContDataSet</code>). When the continuation 
+is called back, the continuation and an event are passed to the handler function. 
+The continuation is a handle to the same continuation that is invoked. The 
+handler function typically has a switch statement to handle the events it receives: </p>
+<div class="codehilite"><pre>    <span class="k">static</span> <span class="kt">int</span> <span class="nf">some_handler</span> <span class="p">(</span><span class="n">TScont</span> <span class="n">contp</span><span class="p">,</span> <span class="n">TSEvent</span> <span class="n">event</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">edata</span><span class="p">)</span>
+    <span class="p">{</span>
+        <span class="p">.....</span>
+            <span class="k">switch</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="p">{</span>
+                <span class="k">case</span> <span class="n">TS_EVENT_SOME_EVENT_1</span>:
+                    <span class="n">do_some_thing_1</span><span class="p">;</span>
+                    <span class="k">return</span><span class="p">;</span>
+                <span class="k">case</span> <span class="n">TS_EVENT_SOME_EVENT_2</span>:
+                    <span class="n">do_some_thing_2</span><span class="p">;</span>
+                    <span class="k">return</span><span class="p">;</span>
+                <span class="k">case</span> <span class="n">TS_EVENT_SOME_EVENT_3</span>:
+                    <span class="n">do_some_thing_3</span><span class="p">;</span>
+                    <span class="k">return</span><span class="p">;</span>
+                <span class="nl">default:</span> <span class="k">break</span><span class="p">;</span>
+            <span class="p">}</span>
+        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
+    <span class="p">}</span>
+</pre></div>
+
+
+<p><img alt="[Caution]" src="/images/docbook/caution.png" /></p>
+<p><strong>Caution</strong> </p>
+<p>You might notice that a continuation cannot determine if more events are "in 
+flight" toward it. Do not use <code>TSContDestroy</code> to delete a continuation before 
+you make sure that all incoming events, such as those sent because of <code>TSHttpTxnHookAdd</code>, 
+have been handled.</p>
+<p>The following table lists events and the corresponding type of <code>void *</code>data 
+passed to handler functions:</p>
+<dl>
+<dt><code>TS_EVENT_HTTP_READ_REQUEST_HDR</code></dt>
+<dd><code>TS_HTTP_READ_REQUEST_HDR_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_HTTP_OS_DNS</code></dt>
+<dd><code>TS_HTTP_OS_DNS_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_HTTP_SEND_REQUEST_HDR</code></dt>
+<dd><code>TS_HTTP_SEND_REQUEST_HDR_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_HTTP_READ_CACHE_HDR</code></dt>
+<dd><code>TS_HTTP_READ_CACHE_HDR_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_HTTP_READ_RESPONSE_HDR</code></dt>
+<dd><code>TS_HTTP_READ_RESPONSE_HDR_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_HTTP_SEND_RESPONSE_HDR</code></dt>
+<dd><code>TS_HTTP_SEND_RESPONSE_HDR_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_HTTP_SELECT_ALT</code></dt>
+<dd><code>TS_HTTP_SELECT_ALT_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_HTTP_TXN_START</code></dt>
+<dd><code>TS_HTTP_TXN_START_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_HTTP_TXN_CLOSE</code></dt>
+<dd><code>TS_HTTP_TXN_CLOSE_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_HTTP_SSN_START</code></dt>
+<dd><code>TS_HTTP_SSN_START_HOOK</code></dd>
+<dd><code>TSHttpSsn</code></dd>
+<dt><code>TS_EVENT_HTTP_SSN_CLOSE</code></dt>
+<dd><code>TS_HTTP_SSN_CLOSE_HOOK</code></dd>
+<dd><code>TSHttpSsn</code></dd>
+<dt><code>TS_EVENT_NONE</code></dt>
+<dd><code /></dd>
+<dd><code /></dd>
+<dt><code>TS_EVENT_CACHE_LOOKUP_COMPLETE</code></dt>
+<dd><code>TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK</code></dd>
+<dd><code>TSHttpTxn</code></dd>
+<dt><code>TS_EVENT_IMMEDIATE</code></dt>
+<dd><code>TSVConnClose, TSVIOReenable, TSContSchedule</code></dd>
+<dd><code /></dd>
+<dt><code>TS_EVENT_IMMEDIATE</code></dt>
+<dd><code>TS_HTTP_REQUEST_TRANSFORM_HOOK</code></dd>
+<dd><code /></dd>
+<dt><code>TS_EVENT_IMMEDIATE</code></dt>
+<dd><code>TS_HTTP_RESPONSE_TRANSFORM_HOOK</code></dd>
+<dd><code /></dd>
+<dt><code>TS_EVENT_CACHE_OPEN_READ</code></dt>
+<dd><code>TSCacheRead</code></dd>
+<dd>Cache VC</dd>
+<dt><code>TS_EVENT_CACHE_OPEN_READ_FAILED</code></dt>
+<dd><code>TSCacheRead</code></dd>
+<dd>Error code, see <code>TS_CACHE_ERROR_XXX</code></dd>
+<dt><code>TS_EVENT_CACHE_OPEN_WRITE</code></dt>
+<dd><code>TSCacheWrite</code></dd>
+<dd>Cache VC</dd>
+<dt><code>TS_EVENT_CACHE_OPEN_WRITE_FAILED</code></dt>
+<dd><code>TSCacheWrite</code></dd>
+<dd>Error code, see <code>TS_CACHE_ERROR_XXX</code></dd>
+<dt><code>TS_EVENT_CACHE_REMOVE</code></dt>
+<dd><code>TSCacheRemove</code></dd>
+<dd>Nothing</dd>
+<dt><code>TS_EVENT_CACHE_REMOVE_FAILED</code></dt>
+<dd><code>TSCacheRemove</code></dd>
+<dd>Error code, see <code>TS_CACHE_ERROR_XXX</code></dd>
+<dt><code>TS_EVENT_NET_ACCEPT</code></dt>
+<dd>
+<p>TSNetAccept, TSHttpTxnServerIntercept,
+              TSHttpTxnIntercept:   Net VConnection</p>
+</dd>
+<dt><code>TS_EVENT_NET_ACCEPT_FAILED</code></dt>
+<dd>
+<div class="codehilite"><pre><span class="n">TSNetAccept</span><span class="p">,</span> <span class="n">TSHttpTxnServerIntercept</span><span class="p">,</span>
+              <span class="n">TSHttpTxnIntercept:</span>   <span class="n">Nothing</span>
+</pre></div>
+
+
+</dd>
+<dt><code>TS_EVENT_HOST_LOOKUP</code></dt>
+<dd>
+<p><code>TSHostLookup</code></p>
+</dd>
+<dd>
+<p>Null pointer - error Non null pointer - <code>TSHostLookupResult</code></p>
+</dd>
+<dt><code>TS_EVENT_TIMEOUT</code></dt>
+<dd>
+<p><code>TSContSchedule</code></p>
+</dd>
+<dd>
+<p><code /></p>
+</dd>
+<dt><code>TS_EVENT_ERROR</code></dt>
+<dd>
+<p><code /></p>
+</dd>
+<dd>
+<p><code /></p>
+</dd>
+<dt><code>TS_EVENT_VCONN_READ_READY</code></dt>
+<dd>
+<p><code>TSVConnRead</code></p>
+</dd>
+<dd>
+<p><code>TSVConn</code></p>
+</dd>
+<dt><code>TS_EVENT_VCONN_WRITE_READY</code></dt>
+<dd>
+<p><code>TSVConnWrite</code></p>
+</dd>
+<dd>
+<p><code>TSVConn</code></p>
+</dd>
+<dt><code>TS_EVENT_VCONN_READ_COMPLETE</code></dt>
+<dd>
+<p><code>TSVConnRead</code></p>
+</dd>
+<dd>
+<p><code>TSVConn</code></p>
+</dd>
+<dt><code>TS_EVENT_VCONN_WRITE_COMPLETE</code></dt>
+<dd>
+<p><code>TSVConnWrite</code></p>
+</dd>
+<dd>
+<p><code>TSVConn</code></p>
+</dd>
+<dt><code>TS_EVENT_VCONN_EOS</code></dt>
+<dd>
+<p><code>TSVConnRead</code></p>
+</dd>
+<dd>
+<p><code>TSVConn</code></p>
+</dd>
+<dt><code>TS_EVENT_NET_CONNECT</code></dt>
+<dd>
+<p><code>TSNetConnect</code></p>
+</dd>
+<dd>
+<p><code>TSVConn</code></p>
+</dd>
+<dt><code>TS_EVENT_NET_CONNECT_FAILED</code></dt>
+<dd>
+<p><code>TSNetConnect</code></p>
+</dd>
+<dd>
+<p><code>TSVConn</code></p>
+</dd>
+<dt><code>TS_EVENT_HTTP_CONTINUE</code></dt>
+<dd>
+<p><code /></p>
+</dd>
+<dd>
+<p><code /></p>
+</dd>
+<dt><code>TS_EVENT_HTTP_ERROR</code></dt>
+<dd>
+<p><code /></p>
+</dd>
+<dd>
+<p><code /></p>
+</dd>
+<dt><code>TS_EVENT_MGMT_UPDATE</code></dt>
+<dd>
+<p><code>TSMgmtUpdateRegister</code></p>
+</dd>
+<dd>
+<p><code>NULL</code></p>
+</dd>
+</dl>
+<p>The continuation functions are listed below:</p>
+<ul>
+<li>
+<p><code>TSContCall</code></p>
+</li>
+<li>
+<p><code>TSContCreate</code></p>
+</li>
+<li>
+<p><code>TSContDataGet</code></p>
+</li>
+<li>
+<p><code>TSContDataSet</code></p>
+</li>
+<li>
+<p><code>TSContDestroy</code></p>
+</li>
+<li>
+<p><code>TSContMutexGet</code></p>
+</li>
+<li>
+<p><code>TSContSchedule</code></p>
+</li>
+</ul>
   </div>
 
   <div id="footer">

Modified: websites/staging/trafficserver/trunk/content/docs/trunk/sdk/plugin-configurations/index.en.html
==============================================================================
--- websites/staging/trafficserver/trunk/content/docs/trunk/sdk/plugin-configurations/index.en.html (original)
+++ websites/staging/trafficserver/trunk/content/docs/trunk/sdk/plugin-configurations/index.en.html Tue Feb  8 00:01:11 2011
@@ -6,8 +6,8 @@
     
     <link rel="stylesheet" href="/styles/pygments_style.css" />
     
-    <title></title>
-    
+    <title>Apache Traffic Server™ Software Developers Kit</title>
+    <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file to you under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with the License.  You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License. -->
   </head>
 
   <body>
@@ -15,11 +15,101 @@
 	    <span id="ts_logo">
 		  <a href="http://trafficserver.apache.org/"><img alt="Apache Traffic Server" src="/images/ts75.png" /></a>
 	  </span>
-	    <h1></h1>
+	    <h1>Apache Traffic Server™ Software Developers Kit</h1>
     </div>
 
   <div id="content">
-      
+      <p><a href="../continuations/writing-handler-functions">Prev</a> - Writing Handler Functions</p>
+<p>Actions Guide - <a href="../actions-guide">Next</a></p>
+<h2 id="PluginConfigurations">Plugin Configurations</h2>
+<p>This chapter contains the following section:</p>
+<ul>
+<li><a href="#PluginConfigurations">Plugin Configurations</a></li>
+</ul>
+<h2 id="PluginConfigurations_1">Plugin Configurations</h2>
+<p>The <code>TSConfig</code> family of functions provides a mechanism for accessing and 
+changing global configuration information within a plugin.</p>
+<p>The functions discussed in this section do not examine or modify Traffic Server 
+configuration variables. To examine Traffic Server configuration and statistics 
+variables, see <a href="../plugin-management/reading-trafficserver-settings-and-statistics">"Reading Traffic Server Settings and Statistics"</a></p>
+<p>The <code>TSConfig</code> family of functions is designed to provide a fast and efficient 
+mechanism for accessing and changing global configuration information within 
+a plugin. Such a mechanism is simple enough to provide in a single-threaded 
+program, but the translation to a multi-threaded program such as Traffic Server 
+is difficult. A common technique is to have a single mutex protect the global 
+configuration information; however, the problem with this solution is that 
+a single mutex becomes a performance bottleneck very quickly.</p>
+<p>The <code>TSConfig</code> family of functions define an interface to storing and retrieving 
+an opaque data pointer. Internally, Traffic Server maintains reference count 
+information about the data pointer so that a call to <code>TSConfigSet</code> will not 
+disturb another thread using the current data pointer. The philosophy is that 
+once a user has a hold of the configuration pointer, it is okay for it to be 
+used even if the configuration changes; all that a user typically wants is 
+a non-changing snapshot of the configuration. You should use <code>TSConfigSet</code> 
+for all global data updates.</p>
+<p>Here's how the interface works:</p>
+<div class="codehilite"><pre><span class="cm">/* Assume that you have previously defined a plugin configuration</span>
+<span class="cm"> * data structure named ConfigData, along with its constructor</span>
+<span class="cm"> * plugin_config_allocator () and its destructor </span>
+<span class="cm"> * plugin_config_destructor (ConfigData *data)</span>
+<span class="cm"> */</span>
+<span class="n">ConfigData</span> <span class="o">*</span><span class="n">plugin_config</span><span class="p">;</span>
+
+<span class="cm">/* You will need to assign plugin_config a unique identifier of type</span>
+<span class="cm"> * unsigned int. It is important to initialize this identifier to zero</span>
+<span class="cm"> * (see the documentation of the  function). </span>
+<span class="cm"> */</span>
+<span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">int</span>   <span class="n">my_id</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
+
+<span class="cm">/* You will need an TSConfig pointer to access a snapshot of the </span>
+<span class="cm"> * current plugin_config. </span>
+<span class="cm"> */</span>
+<span class="n">TSConfig</span> <span class="n">config_ptr</span><span class="p">;</span>
+
+<span class="cm">/* Initialize plugin_config. */</span>
+<span class="n">plugin_config</span> <span class="o">=</span> <span class="n">plugin_config_allocator</span><span class="p">();</span>
+
+<span class="cm">/* Assign plugin_config an identifier using TSConfigSet. */</span>
+<span class="n">my_id</span> <span class="o">=</span> <span class="n">TSConfigSet</span> <span class="p">(</span><span class="n">my_id</span><span class="p">,</span> <span class="n">plugin_config</span><span class="p">,</span> <span class="n">plugin_config_destructor</span><span class="p">);</span>
+
+<span class="cm">/* Get a snapshot of the current configuration using TSConfigGet. */</span>
+<span class="n">config_ptr</span> <span class="o">=</span> <span class="n">TSConfigGet</span> <span class="p">(</span><span class="n">my_id</span><span class="p">);</span>
+
+<span class="cm">/* With an TSConfig pointer to the current configuration, you can </span>
+<span class="cm"> * retrieve the configuration&#39;s current data using TSConfigDataGet. </span>
+<span class="cm"> */</span>
+<span class="n">plugin_config</span> <span class="o">=</span> <span class="p">(</span><span class="n">ConfigData</span><span class="o">*</span><span class="p">)</span> <span class="n">TSConfigDataGet</span> <span class="p">(</span><span class="n">config_ptr</span><span class="p">);</span>
+
+<span class="cm">/* Do something with plugin_config here. */</span>
+
+<span class="cm">/* When you are done with retrieving or modifying the plugin data, you</span>
+<span class="cm"> * release the pointers to the data with a call to TSConfigRelease.</span>
+<span class="cm"> */</span>
+<span class="n">TSConfigRelease</span> <span class="p">(</span><span class="n">my_id</span><span class="p">,</span> <span class="n">config_ptr</span><span class="p">);</span>
+
+<span class="cm">/* Any time you want to modify plugin_config, you must repeat these</span>
+<span class="cm"> * steps, starting with </span>
+<span class="cm"> * my_id = TSConfigSet (my_id,plugin_config, plugin_config_destructor);</span>
+<span class="cm"> * and continuing up to TSConfigRelease. </span>
+<span class="cm"> */</span>
+</pre></div>
+
+
+<p>The configuration functions are:</p>
+<ul>
+<li>
+<p><a href="link/to/doxygen"><code>TSConfigDataGet</code></a></p>
+</li>
+<li>
+<p><a href="link/to/doxygen"><code>TSConfigGet</code></a></p>
+</li>
+<li>
+<p><a href="link/to/doxygen"><code>TSConfigRelease</code></a></p>
+</li>
+<li>
+<p><a href="link/to/doxygen"><code>TSConfigSet</code></a></p>
+</li>
+</ul>
   </div>
 
   <div id="footer">