html updates
[clinton/website/site/unknownlamer.org.git] / UCWNotes.html
CommitLineData
2aff8b5c 1<?xml version="1.0" encoding="utf-8" ?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
6 <title>Roadmap to UCW Codebase</title>
7 <meta name="generator" content="muse.el" />
8 <meta http-equiv="Content-Type"
9 content="text/html; charset=utf-8" />
7404d4e1 10 <link href="http://feeds.unknownlamer.org/rss/site-updates"
11 rel="alternate" type="application/rss+xml" title="Updates Feed" />
12
13<link rel="stylesheet" href="default.css" />
2aff8b5c 14 </head>
15 <body>
16 <h1>Roadmap to UCW Codebase</h1>
17 <div class="contents">
18<dl>
19<dt>
20<a href="#sec1">Abstract</a>
21</dt>
22<dt>
23<a href="#sec2">Roadmap</a>
24</dt>
25<dd>
26<dl>
27<dt>
28<a href="#sec3">Applications</a>
29</dt>
30<dd>
31<dl>
32<dt>
33<a href="#sec4">Cookie</a>
34</dt>
35<dt>
36<a href="#sec5">L10n</a>
37</dt>
38<dt>
39<a href="#sec6">Secure</a>
40</dt>
41</dl>
42</dd>
43<dt>
44<a href="#sec7">Components</a>
45</dt>
46<dd>
47<dl>
48<dt>
49<a href="#sec8">Windows</a>
50</dt>
51<dt>
52<a href="#sec9">Containers</a>
53</dt>
54<dt>
55<a href="#sec10">Dialogs</a>
56</dt>
57<dt>
58<a href="#sec11">Forms</a>
59</dt>
60<dt>
61<a href="#sec12">Templates</a>
62</dt>
63<dt>
64<a href="#sec13">Utility Mixin Components</a>
65</dt>
66</dl>
67</dd>
68<dt>
69<a href="#sec14">Control Flow</a>
70</dt>
71<dd>
72<dl>
73<dt>
74<a href="#sec15">Calling</a>
75</dt>
76<dt>
77<a href="#sec16">Actions</a>
78</dt>
79<dt>
80<a href="#sec17">Entry Points</a>
81</dt>
82</dl>
83</dd>
84<dt>
85<a href="#sec18">Dispatching</a>
86</dt>
87<dd>
88<dl>
89<dt>
90<a href="#sec19">Simple Dispatcher</a>
91</dt>
92</dl>
93</dd>
94<dt>
95<a href="#sec20">Server</a>
96</dt>
97<dt>
98<a href="#sec21">Debugging</a>
99</dt>
100<dd>
101<dl>
102<dt>
103<a href="#sec22">Inspector</a>
104</dt>
105</dl>
106</dd>
107</dl>
108</dd>
109<dt>
110<a href="#sec23">Tips</a>
111</dt>
112<dd>
113<dl>
114<dt>
115<a href="#sec24">Getting dojo to load</a>
116</dt>
117<dt>
118<a href="#sec25">Specials Bound During Rendering</a>
119</dt>
120<dt>
121<a href="#sec26">Printing to the yaclml stream</a>
122</dt>
123</dl>
124</dd>
125</dl>
126</div>
127
128
129<!-- Page published by Emacs Muse begins here --><h2><a name="sec1" id="sec1"></a>
130Abstract</h2>
131
132<p><a href="http://common-lisp.net/project/ucw/">UnCommon Web</a> is a very powerful and mature web framework for Common
133Lisp, but is a bit difficult to learn. It is documented
134extensively&mdash;in the form of docstrings. These are extremely helpful
135once you've figured out the rough structure of UCW, but they are of no
136help when first learning unless you just read most of the source. I
137ended up having to do that, and after some urging along by folks in
138<code>#ucw</code> I decided to clean up my planner notes and publish them for
139public consumption.</p>
140
141<p>The roadmap is presented with major sections ordered in a logical
142order for learning the framework. The sections are ordered internally
143in order of most immediately useful to least, but it may be worth
144hopping between major sections before reading all of the details. I
145have used abridged class definitions and docstrings with occasional
146commentary to clarify things.</p>
147
148
149<h2><a name="sec2" id="sec2"></a>
150Roadmap</h2>
151
152<h3><a name="sec3" id="sec3"></a>
153Applications</h3>
154
155<p class="first">Applications are a bundle of entry points. The base class is,
156naturally, <code>standard-application</code>, but you should instead derive your
157application class from <code>modular-application</code> and any standard or custom
158application mixins you find useful.</p>
159
160<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-classes.lisp">src/rerl/standard-classes.lisp</a></p>
161
162<pre class="src">
7404d4e1 163(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">standard-application</span> (application)
164 ((url-prefix <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:url-prefix</span>
165 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"A string specifying the
2aff8b5c 166start (prefix) of all the urls this app should handle.
167
168This value is used by the standard-server to decide what app a
169particular request is aimed at and for generating links to
170actions within the app. "</span>)
7404d4e1 171 (www-roots <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:www-roots</span>
172 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"A list of directories (pathname
2aff8b5c 173specifiers) or cons-cell (URL-subdir . pathname) to use when looking for static files."</span>)
7404d4e1 174 (dispatchers <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:dispatchers</span>
175 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"A list of request
2aff8b5c 176dispatchers. The user supplied list of dispatchers is extended
177with other dispatchers that are required for UCW to function
178properly (action-dispatcher, a parenscript-dispatcher, etc). If
179you want full control over the active dispatchers use the (setf
180application.dispatchers) accessor or, if you want control over
181the order of the dispathcers, (slot-value instance
182'dispatchers)."</span>))
7404d4e1 183 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"The default UCW application class."</span>))
2aff8b5c 184</pre>
185
186<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/modular-application/modular-application.lisp">src/rerl/modular-application/modular-application.lisp</a></p>
187
188<pre class="src">
7404d4e1 189(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">modular-application-mixin</span> ()
2aff8b5c 190 ()
7404d4e1 191 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Superclass for all application mixins."</span>))
2aff8b5c 192
7404d4e1 193(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">modular-application</span> (standard-application modular-application-mixin)
2aff8b5c 194 ...)
195</pre>
196
197<h4><a name="sec4" id="sec4"></a>
198Cookie</h4>
199
200<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/modular-application/cookie-module.lisp">src/rerl/modular-application/cookie-module.lisp</a></p>
201
202<pre class="src">
7404d4e1 203(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">cookie-session-application-module</span> (modular-application-mixin)
204 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Class for applications which use cookies for sesion tracking.
2aff8b5c 205
206Cookie session applications work exactly like
207standard-applications except that when the session is not found
208using the standard mechanisms the id is looked for in a cookie."</span>))
209</pre>
210
211<p>This is the most useful of the application components. It makes your
212application urls readable by stashing the session id into a cookie
213rather than as a set of long and ugly GET parameters.</p>
214
215
216<h4><a name="sec5" id="sec5"></a>
217L10n</h4>
218
219<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/modular-application/l10n-module.lisp">src/rerl/modular-application/l10n-module.lisp</a></p>
220
221<pre class="src">
7404d4e1 222(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">l10n-application-module</span> (modular-application-mixin)
223 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Application class which can handle l10n requests."</span>))
2aff8b5c 224</pre>
225
226
227<h4><a name="sec6" id="sec6"></a>
228Secure</h4>
229
230<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/modular-application/security-module.lisp">src/rerl/modular-application/security-module.lisp</a></p>
231
232<pre class="src">
7404d4e1 233(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">secure-application-module</span> (modular-application-mixin)
234 (<span class="emacs-face-builtin">:documentation</span>
235 <span class="emacs-face-string">"Mixin class for applications which require authorized access.
2aff8b5c 236Concrete application must specialize the following methods:
237APPLICATION-FIND-USER (APPLICATION USERNAME)
238APPLICATION-CHECK-PASSWORD (APPLICATION USER PASSWORD)
239APPLICATION-AUTHORIZE-CALLZE-CALL (APPLICATION USER FROM-COMPONENT TO-COMPONENT)."</span>))
240</pre>
241
242
243
244<h3><a name="sec7" id="sec7"></a>
245Components</h3>
246
247<p class="first">A component is a special class that handles the complexities of
248continuation suspension and such for you. New components are derived
249from the existing ones by using <code>defcomponent</code> instead of <code>defclass</code>. This
250adds a few extra slot and class options, and ensures that the proper
251metaclass is set.</p>
252
253<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-component/standard-component.lisp">src/rerl/standard-component/standard-component.lisp</a></p>
254
255<pre class="src">
7404d4e1 256(<span class="emacs-face-keyword">defmacro</span> <span class="emacs-face-function-name">defcomponent</span> (name supers slots <span class="emacs-face-type">&amp;rest</span> options)
257 <span class="emacs-face-doc">"Macro for defining a component class.
2aff8b5c 258
259This macro is used to create component classes and provides
260options for easily creating the methods which often accompany a
261component definition.
262
263NAME, SUPERS and SLOTS as treated as per defclass. The following
264extra options are allowed:
265
266 (:ENTRY-POINT url (&amp;key application class)) - Define an
267 entry-point on the url URL which simply calls an instance of
268 this component. Any request parameters passed to the entry-point
269 are used to initialize the slots in the component. This option
270 may appear multiple times.
271
272 (:DEFAULT-BACKTRACK function-designator) - Unless the slots
273 already have a :backtrack option FUNCTION-DESIGNATOR is
274 added. As with the 'regular' :backtrack options if you pass T
275 here it is assumed to mean #'IDENTITY.
276
277 (:RENDER (&amp;optional COMPONENT) &amp;body BODY) - Generate a render
278 method specialized to COMPONENT. COMPONENT may be a symbol, in
279 which case the method will be specialized on the componnet
280 class. If COMPONNET is omited the component is bound to a
281 variable with the same name as the class.
282
283 (:ACTION &amp;optional NAME) - Generate a defaction form named
284 NAME (which defaults to the name of the component) which simply
285 CALL's this component class passing all the arguments passed to
286 the action as initargs."</span>)
287
7404d4e1 288<span class="emacs-face-comment-delimiter">;;; </span><span class="emacs-face-comment">Extra Slot Options
289</span><span class="emacs-face-string">"Other than the initargs for standard slots the following
2aff8b5c 290options can be passed to component slots:
291
292:backtrack [ T | NIL | FUNCTION-NAME ] - Specify that this slot
293should be backtracked (or not if NIL is passed as the value). If
294the value is neither T nor NIL then it must be a function which
295will be used as the copyer.
296
297:component [ TYPE | ( TYPE &amp;rest INITARGS ) ] - Specify that this
298slot is actually a nested component of type TYPE. When instances
299of the class are created this slot will be set to an instance of
300type TYPE and it's place will be set to this slot. If a list is
301passed to :component then TYPE (which isn't evaluated) will be
302passed as the first argument to make-instance. The INITARGS will
303be eval'd and apply'd to make-instance. The result of this call
304to make-instance will be used as the effective component
305object."</span>
306</pre>
307
308<h4><a name="sec8" id="sec8"></a>
309Windows</h4>
310
311<p class="first">A window-component represents a top level browser window, naturally.</p>
312
313<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/window.lisp">src/components/window.lisp</a></p>
314
315<pre class="src">
7404d4e1 316(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">window-component</span> ()
2aff8b5c 317 ((content-type)))
318
7404d4e1 319(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">simple-window-component</span> (window-component)
2aff8b5c 320 ((title)
321 (stylesheet)
7404d4e1 322 (javascript <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"List of javascript includes.
2aff8b5c 323
324Each element must be a list whose first value is either the
325symbol :SRC or :JS.
326
327 (:SRC url) - writes &lt;script src=\"URL\"&gt;&lt;/script&gt; tag.
328 (:JS form) - equivalent to (:SCRIPT (js:js* form))
329 (:SCRIPT string) - write &lt;script&gt;STRING&lt;/script&gt;.
330
331The elements will be rendered in order."</span>)
332 ...))
333</pre>
334
335<p><code>window-component</code> could be useful for doing things like dumping binary
336data to the user, or just deriving your own funky top level window
337type.</p>
338
339<p><code>simple-window-component</code> is the easiest for displaying standard
340webpage. It provides a wrapping method on render that displays the
341html boilerplate based on your component slot values which is what one
342wants most of the time. The initargs to <code>simple-window-component</code> have
343the same names as the slots.</p>
344
345<h5>Status Bar</h5>
346
347<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/status-bar.lisp">src/components/status-bar.lisp</a></p>
348
349<p>There is a generic status bar interface. Messages severity is one of
350<code>(:error :warn :info)</code>. Note that the default status bar render method
351just shows a div with status messages. A derivative could be defined
352to insert messages into the browser status bar.</p>
353
354<pre class="src">
355(defcomponent status-bar ()
7404d4e1 356 ((messages <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"An ALIST of the messages to
2aff8b5c 357show. Each element is a cons of the form (SEVERITY .
358MESSAGE). SEVERITY is one of :ERROR, :WARN, :INFO and MESSAGE is
359a string which will be html-escaped."</span>)
360 ...)
7404d4e1 361 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Stateless status bar to display messages."</span>))
2aff8b5c 362
7404d4e1 363(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">add-message</span> (status-bar msg <span class="emacs-face-type">&amp;key</span> severity <span class="emacs-face-type">&amp;allow-other-keys</span>)
364 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Add the message text MSG to STATUS-BAR with
2aff8b5c 365severity SEVERITY."</span>))
366</pre>
367
368<pre class="src">
369(defcomponent status-bar-mixin ()
7404d4e1 370 ((status-bar <span class="emacs-face-builtin">:accessor</span> status-bar
371 <span class="emacs-face-builtin">:initarg</span> status-bar
372 <span class="emacs-face-builtin">:component</span> (status-bar))))
2aff8b5c 373
7404d4e1 374(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">show-status-bar</span> ((win status-bar-mixin))
2aff8b5c 375 (render (status-bar win)))
376
7404d4e1 377(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">show-message</span> (msg <span class="emacs-face-type">&amp;key</span> severity <span class="emacs-face-type">&amp;allow-other-keys</span>)
378 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Show a message in the status bar. Only works if
2aff8b5c 379 current window is a status-bar-mixin"</span>))
380</pre>
381
382
383<h5>Redirect</h5>
384
385<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/redirect.lisp">src/components/redirect.lisp</a></p>
386
387<pre class="src">
7404d4e1 388(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">redirect-component</span> ()
389 ((target <span class="emacs-face-builtin">:accessor</span> target <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:target</span>))
390 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class)
391 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Send a client redirect.
2aff8b5c 392
393This component, which must be used as a window-component,
394redirects the client to the url specified in the target slot. A
395302 (as opposed to 303) response code is sent to ensure
396compatability with older browsers.
397
398The redirect component never answers."</span>))
399</pre>
400
401<p>There is also a <code>meta-refresh</code> procedure.</p>
402
403<pre class="src">
404(defun/cc meta-refresh ()
7404d4e1 405 <span class="emacs-face-string">"Cause a meta-refresh (a freshly got (GET) url) at this point.
2aff8b5c 406This is useful in order to have a GET url after a form POST's
407actions have completed running. The user can then refresh to his
408heart's content."</span>)
409</pre>
410
411
412
413<h4><a name="sec9" id="sec9"></a>
414Containers</h4>
415
416<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/container.lisp">src/components/container.lisp</a></p>
417
418<pre class="src">
7404d4e1 419(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">container</span> ()
2aff8b5c 420 (...)
7404d4e1 421 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class)
422 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Allow multiple components to share the same place.
2aff8b5c 423
424The container component serves to manage a set of components.
425It does not provide any render impementation, which is the
426resposibility of the subclasses (e.g. switching-container or
427list-container).
428
429Each contained component has a \"key\" associated with it which
430is used to retrieve a particular component. Keys are compared with
431container.key-test.
432
433The :contents inintarg, if provided, must be either a list of (key .
434component) or a list of components. In the latter case it will
435be converted into (component . component) form."</span>))
436</pre>
437
438<h5>Protocol</h5>
439
440<ul>
441<li><code>child-components</code></li>
442<li><code>find-component CONTAINER KEY</code></li>
443<li><code>remove-component</code></li>
444<li><code>(setf find-component CONTAINER KEY) COMPONENT</code> -&gt;
445<code>add-component CONTAINER COMPONENT KEY</code></li>
446</ul>
447
448
449<h5>Switching Container</h5>
450
451<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/container.lisp">src/components/container.lisp</a></p>
452
453<pre class="src">
7404d4e1 454(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">switching-container</span> ...
455 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"A simple renderable container component.
2aff8b5c 456
457This component is like the regular CONTAINER but serves to manage a set
458of components which share the same place in the UI. Therefore it provides
459an implementation of RENDER which simply renders its current component.
460
461The switching-container component class is generally used as the super
462class for navigatation components and tabbed-pane like
463components."</span>))
464</pre>
465
466<p>Subclass and <code>(defmethod render :around ...)</code> to render navigation using
467<code>(call-next-method)</code> to render the selected component.</p>
468
469<h5>Protocol</h5>
470
471<ul>
472<li><code>container.current-component COMPONENT</code></li>
473<li><code>(setf container.current-component CONTAINER) COMPONENT</code></li>
474</ul>
475
476
477
478<h5>Tabbed Pane</h5>
479
480<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/tabbed-pane.lisp">src/components/tabbed-pane.lisp</a></p>
481
482<pre class="src">
483(defcomponent tabbed-pane (switching-container)
7404d4e1 484 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Component for providing the user with a standard \"tabbed pane\" GUI widget."</span>))
2aff8b5c 485</pre>
486
487<p>Provides a generic tabbed pane that renders a nested div split into a
488naviation and content box. The navigation box is a set of styled divs
489containing the navigation links.</p>
490
491
492
493<h4><a name="sec10" id="sec10"></a>
494Dialogs</h4>
495
496<p class="first">A few convenience dialogs are provided for grabbing data from the
497user.</p>
498
499<h5>login</h5>
500
501<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/login.lisp">src/components/login.lisp</a></p>
502
503<pre class="src">
7404d4e1 504(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">login</span> ()
2aff8b5c 505 ((username) (password) (message))
7404d4e1 506 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Generic login (input username and password) component.
2aff8b5c 507
508This component, which must be embedded in another component,
509presents the user with a simple two fielded login form.
510
511When the user attempts a login the action try-login is called,
512try-login calls the generic function check-credentials passing it
513the login component. If check-credentials returns true then the
514login-successful action is called, otherwise the message slot of
515the login component is set (to a generic \"bad username\"
516message).
517
518The default implementaion of login-successful simply answers t,
519no default implementation of check-credentials is
520provided. Developers should use sub-classes of login for which
521all the required methods have been definined."</span>)
7404d4e1 522 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 523</pre>
524
525<pre class="src">
7404d4e1 526(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">check-credentials</span> (login)
527 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Returns T if LOGIN is valid."</span>))
2aff8b5c 528
529(defaction login-successful ((l login))
530 (answer t))
531</pre>
532
533<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/user-login.lisp">src/components/user-login.lisp</a></p>
534
535<pre class="src">
536(defcomponent user-login (simple-window-component status-bar-mixin)
537 ((username string-field) (password password-field)))
538</pre>
539
540<p>Used by <code>secure-application-module</code> to provide a user login. Relevant
541protocol details follow.</p>
542
543<pre class="src">
7404d4e1 544(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">check-credentials</span> ((self user-login))
545 (<span class="emacs-face-keyword">let*</span> ((username (value (username self)))
2aff8b5c 546 (password (value (password self)))
547 (user (find-application-user username)))
7404d4e1 548 (<span class="emacs-face-keyword">when</span> (and user (check-user-password user password))
2aff8b5c 549 user)))
550
7404d4e1 551(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">application-find-user</span> (application username)
552 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Find USER by USERNAME for APPLICATION."</span>))
2aff8b5c 553</pre>
554
555
556<h5>error</h5>
557
558<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/error.lisp">src/components/error.lisp</a></p>
559
560<pre class="src">
7404d4e1 561(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">error-message</span> (simple-window-component)
562 ((message <span class="emacs-face-builtin">:accessor</span> message <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:message</span> <span class="emacs-face-builtin">:initform</span> <span class="emacs-face-string">"ERROR [no message specified]"</span>))
563 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Generic component for showing server side
2aff8b5c 564 error messages."</span>)
7404d4e1 565 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 566
7404d4e1 567(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">error-component</span> (error-message)
568 ((condition <span class="emacs-face-builtin">:accessor</span> error.condition <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:condition</span> <span class="emacs-face-builtin">:initform</span> nil)
569 (backtrace <span class="emacs-face-builtin">:accessor</span> error.backtrace <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:backtrace</span>))
570 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Generic component for showing server side
2aff8b5c 571 error conditions. Unlike ERROR-MESSAGE this component also
572 attempts to display a backtrace."</span>)
7404d4e1 573 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 574</pre>
575
576
577<h5>message</h5>
578
579<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/message.lisp">src/components/message.lisp</a></p>
580
581<pre class="src">
7404d4e1 582(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">info-message</span> ()
583 ((message <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:message</span> <span class="emacs-face-builtin">:accessor</span> message)
584 (ok-text <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:ok-text</span> <span class="emacs-face-builtin">:accessor</span> ok-text <span class="emacs-face-builtin">:initform</span> <span class="emacs-face-string">"Ok."</span>))
585 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Component for showing a message to the user.
2aff8b5c 586
587If the OK-TEXT slot is non-NIL component will use that as the
588text for a link which, when clicked, causes the component to
589answer. It follows that if OK-TEXT is NIL this component will
590never answer."</span>)
7404d4e1 591 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 592</pre>
593
594
595<h5>option-dialog</h5>
596
597<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/option-dialog.lisp">src/components/option-dialog.lisp</a></p>
598
599<pre class="src">
7404d4e1 600(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">option-dialog</span> (template-component)
2aff8b5c 601 ((message) (options) (confirm))
7404d4e1 602 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:template-name</span> <span class="emacs-face-string">"ucw/option-dialog.tal"</span>)
603 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Component for querying the user.
2aff8b5c 604
605The value of the slot MESSAGE is used as a general heading.
606
607The OPTIONS slot must be an alist of (VALUE . LABEL). LABEL (a
608string) will be used as the text of a link which, when clikced,
609will answer VALUE.
610
611If the CONFIRM slot is T the user will be presented with a second
612OPTION-DIALOG asking the user if they are sure they want to
613submit that value."</span>)
7404d4e1 614 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 615</pre>
616
617<p>A macro to present an option dialog is provided.</p>
618
619<pre class="src">
7404d4e1 620(<span class="emacs-face-keyword">defmacro</span> <span class="emacs-face-function-name">option-dialog</span> ((message-spec <span class="emacs-face-type">&amp;rest</span> message-args) <span class="emacs-face-type">&amp;body</span> options)
2aff8b5c 621 ...)
622</pre>
623
624<p><code>message-spec</code> is passed to <code>format</code> if <code>message-args</code> are supplied, and
625used as a string literal otherwise. This does not provide a way to set
626the confirm property which makes the macro not so generally useful.</p>
627
628
629
630<h4><a name="sec11" id="sec11"></a>
631Forms</h4>
632
633<p class="first">Reasonably useful forms library that integrates easily with TAL.</p>
634
635<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/form.lisp">src/components/form.lisp</a></p>
636
637<pre class="src">
7404d4e1 638(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">form-field</span> ()
639 ((validators <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"List of validators which will be
2aff8b5c 640 applied to this field."</span>)
7404d4e1 641 (initially-validate <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"When non-NIL the
2aff8b5c 642 validators will be run as soon as the page
643 is rendered."</span>)))
644
7404d4e1 645(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">value</span> (form-field)
646 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"The lispish translated value that represents the form-field."</span>))
647
648(<span class="emacs-face-keyword">defgeneric</span> (<span class="emacs-face-function-name">setf value)</span> (new-value form-field)
649 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Set the value of a form-field with translation to client."</span>))
650
651(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">generic-html-input</span> (form-field html-element)
652 ((client-value <span class="emacs-face-builtin">:accessor</span> client-value <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:client-value</span>
653 <span class="emacs-face-builtin">:initform</span> <span class="emacs-face-string">""</span>
654 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"The string the client submitted along with this field."</span>)
655 (name <span class="emacs-face-builtin">:accessor</span> name <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:name</span> <span class="emacs-face-builtin">:initform</span> nil)
656 (accesskey <span class="emacs-face-builtin">:accessor</span> accesskey <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:accesskey</span> <span class="emacs-face-builtin">:initform</span> nil)
657 (tooltip <span class="emacs-face-builtin">:accessor</span> tooltip <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:tooltip</span> <span class="emacs-face-builtin">:initform</span> nil)
658 (tabindex <span class="emacs-face-builtin">:accessor</span> tabindex <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:tabindex</span> <span class="emacs-face-builtin">:initform</span> nil))
659 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:dom-id</span> (js:gen-js-name-string <span class="emacs-face-builtin">:prefix</span> <span class="emacs-face-string">"_ucw_"</span>)))
2aff8b5c 660</pre>
661
662<p>Fields are rendered into the extended <code>&lt;ucw:input</code> yaclml tag which
663supports a few fancy features. The <code>:accessor</code> for all form elements is
664set to <code>(client-value FIELD)</code>, and you should use <code>value</code> to access the
665Lisp value associated with it.</p>
666
667<pre class="src">
7404d4e1 668(deftag-macro &lt;ucw:input (<span class="emacs-face-type">&amp;attribute</span> accessor action reader writer name id (default nil)
669 <span class="emacs-face-type">&amp;allow-other-attributes</span> others)
670 <span class="emacs-face-string">"Generic INPUT tag replacement.
2aff8b5c 671
672If the ACCESSOR attribute is specified then it must be a PLACE
673and it's value will be used to fill the input, when the form is
674submitted it will be set to the new value.
675
676If ACTION is specefied then when the form is submitted via this
677input type=\"submit\" tag the form will be eval'd. when the
678submit (or image) is clicked. DEFAULT means that the ACTION
679provided for this input tag will be the default action of the
680form when pressing enter in a form field. If more then one, then
681the latest wins."</span>)
682</pre>
683
684<p>Validation of form fields are supported by adding to the validators
685list.</p>
686
687<pre class="src">
7404d4e1 688(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">validator</span> ()
689 ((message <span class="emacs-face-builtin">:accessor</span> message <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:message</span> <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 690
7404d4e1 691(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">validate</span> (field validator)
692 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Validate a form-field with a validator."</span>))
2aff8b5c 693
7404d4e1 694(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">javascript-check</span> (field validator)
695 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Generate javascript code for checking FIELD against VALIDATOR.
2aff8b5c 696
697This is the convenience entry point to generate-javascript-check,
698methods defined on this generic funcition should return a list of
699javascript code (as per parenscript) which tests against the
700javascript variable value."</span>))
701
7404d4e1 702(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">javascript-invalid-handler</span> (field validator)
703 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"The javascript code body for when a field is invalid."</span>))
2aff8b5c 704
7404d4e1 705(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">javascript-valid-handler</span> (field validator)
706 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Generate the javascript body for when a field is valid."</span>))
2aff8b5c 707</pre>
708
709<h5>Standard Form Fields</h5>
710
711<pre class="src">
7404d4e1 712(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">string-field</span> (generic-html-input)
2aff8b5c 713 ((input-size) (maxlength)))
714
7404d4e1 715(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">password-field</span> (string-field))
716(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">number-field</span> (string-field))
717(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">integer-field</span> (number-field))
2aff8b5c 718
7404d4e1 719(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">in-field-string-field</span> (string-field)
720 ((in-field-label <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"This slot, if non-NIL, will be
2aff8b5c 721 used as an initial field label. An initial
722 field label is a block of text which is placed
723 inside the input element and removed as soon
724 as the user edits the field. Obviously this
725 field is overidden by an initial :client-value
726 argument."</span>)))
727
7404d4e1 728(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">textarea-field</span> (generic-html-input)
2aff8b5c 729 ((rows) (cols)))
730
7404d4e1 731(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">date-field</span> (form-field widget-component)
2aff8b5c 732 ((year) (month) (day)))
733
7404d4e1 734(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">dmy-date-field</span> (date-field)
735 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Date fields which orders the inputs day/month/year"</span>))
736(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">mdy-date-field</span> (date-field))
2aff8b5c 737
7404d4e1 738(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">select-field</span> (generic-html-input)
739 ((data-set <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"The values this select chooses
2aff8b5c 740 from."</span>))
7404d4e1 741 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Form field used for selecting one value from a
2aff8b5c 742 list of available options."</span>))
743
7404d4e1 744(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">render-value</span> (select-field value)
745 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"This function will be passed each value in the field's
2aff8b5c 746 data-set and must produce the body of the corresponding
747 &lt;ucw:option tag."</span>))
748
7404d4e1 749(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">mapping-select-field</span> (select-field)
750 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Class used when we want to chose the values of
2aff8b5c 751 a certain mapping based on the keys. We render the keys in the
752 select and return the corresponding value from the VALUE
753 method."</span>))
754
7404d4e1 755(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">hash-table-select-field</span> (mapping-select-field))
756(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">alist-select-field</span> (mapping-select-field))
757(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">plist-select-field</span> (mapping-select-field))
2aff8b5c 758
7404d4e1 759(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">radio-group</span> (generic-html-input)
2aff8b5c 760 ((value-widgets)))
761
7404d4e1 762(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">radio-button</span> (generic-html-input)
2aff8b5c 763 ((value)
7404d4e1 764 (group <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"The RADIO-GROUP this button is a part
2aff8b5c 765 of."</span>))
7404d4e1 766 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"A widget representing a single radio
2aff8b5c 767 button. Should be used in conjunction with a RADIO-GROUP."</span>))
768
7404d4e1 769(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">add-value</span> ((group radio-group) value)
770 <span class="emacs-face-string">"Adds radio-button with value to group"</span>)
2aff8b5c 771
7404d4e1 772(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">checkbox-field</span> (generic-html-input))
773(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">file-upload-field</span> (generic-html-input))
774(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">submit-button</span> (generic-html-input)
2aff8b5c 775 ((label)))
776</pre>
777
778<h5>File Upload Field</h5>
779
780<p>Calling <code>value</code> on a <code>file-upload-field</code> returns a mime encoded body
781part. <code>(mime-part-body (value FIELD))</code> will return a <strong>binary stream</strong>
782attached to the contents of the file. The <code>Content-Type</code> header should
783be set to the MIME type of the file being uploaded.</p>
784
785<pre class="src">
7404d4e1 786(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">mime-part-headers</span> (mime-part)
787 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Returns an alist of the headers of MIME-PART.
2aff8b5c 788
789The alist must be of the form (NAME . VALUE) where both NAME and
790VALUE are strings."</span>))
791
7404d4e1 792(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">mime-part-body</span> (mime-part)
793 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Returns the body of MIME-PART."</span>))
2aff8b5c 794</pre>
795
796
797
798<h5>Standard Validators</h5>
799
800<pre class="src">
7404d4e1 801(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">not-empty-validator</span> (validator))
2aff8b5c 802
7404d4e1 803(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">value-validator</span> (validator)
804 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Validators that should only be applied if there is a value.
2aff8b5c 805That is, they always succeed on nil."</span>))
806
7404d4e1 807(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">length-validator</span> (value-validator)
808 ((min-length <span class="emacs-face-builtin">:accessor</span> min-length <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:min-length</span>
809 <span class="emacs-face-builtin">:initform</span> nil)
810 (max-length <span class="emacs-face-builtin">:accessor</span> max-length <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:max-length</span>
811 <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 812
7404d4e1 813(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">string=-validator</span> (validator)
814 ((other-field <span class="emacs-face-builtin">:accessor</span> other-field <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:other-field</span>))
815 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Ensures that a field is string= to another one."</span>))
2aff8b5c 816
7404d4e1 817(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">regex-validator</span> (value-validator)
818 ((regex <span class="emacs-face-builtin">:accessor</span> regex <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:regex</span> <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 819
7404d4e1 820(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">e-mail-address-validator</span> (regex-validator))
2aff8b5c 821
7404d4e1 822(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">phone-number-validator</span> (regex-validator))
2aff8b5c 823
7404d4e1 824(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">is-a-number-validator</span> (value-validator))
825(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">is-an-integer-validator</span> (is-a-number-validator))
2aff8b5c 826
7404d4e1 827(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">number-range-validator</span> (is-a-number-validator)
828 ((min-value <span class="emacs-face-builtin">:accessor</span> min-value <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:min-value</span> <span class="emacs-face-builtin">:initform</span> nil)
829 (max-value <span class="emacs-face-builtin">:accessor</span> max-value <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:max-value</span> <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 830</pre>
831
832
833<h5>Simple Form Helper</h5>
834
835<p>UCW provides a helper class for developing forms. Subclass and add the
836elements you wish to include in the form. A <code>:wrapping</code> method renders
837the form boilerplate and then calls your <code>render</code>.</p>
838
839<pre class="src">
840(defcomponent simple-form (html-element)
7404d4e1 841 ((submit-method <span class="emacs-face-builtin">:accessor</span> submit-method
842 <span class="emacs-face-builtin">:initform</span> <span class="emacs-face-string">"post"</span>
843 <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:submit-method</span>)
844 (dom-id <span class="emacs-face-builtin">:accessor</span> dom-id
845 <span class="emacs-face-builtin">:initform</span> (js:gen-js-name-string <span class="emacs-face-builtin">:prefix</span> <span class="emacs-face-string">"_ucw_simple_form_"</span>)
846 <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:dom-id</span>))
847 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:dom-id</span> <span class="emacs-face-string">"ucw-simple-form"</span>))
2aff8b5c 848</pre>
849
850
851
852<h4><a name="sec12" id="sec12"></a>
853Templates</h4>
854
855<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/template.lisp">src/components/template.lisp</a></p>
856
857<p>Infrastructure for loading TAL templates as a view of a component.</p>
858
859<pre class="src">
7404d4e1 860(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">template-component</span> (component))
2aff8b5c 861(defcomponent simple-template-component (template-component)
7404d4e1 862 ((environment <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:environment</span> <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 863
7404d4e1 864(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">template-component-environment</span> (component)
865 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Create the TAL environment for rendering COMPONENT's template.
2aff8b5c 866
867Methods defined on this generic function must return a TAL
868environment: a list of TAL binding sets (see the documentation
869for YACLML:MAKE-STANDARD-ENVIRONMENT for details on TAL
870environments.)"</span>)
7404d4e1 871 (<span class="emacs-face-builtin">:method-combination</span> nconc))
2aff8b5c 872
7404d4e1 873(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">template-component-environment</span> nconc ((component template-component))
874 <span class="emacs-face-string">"Create the basic TAL environment.
2aff8b5c 875
876Binds the symbol ucw:component to the component object itself,
877also puts the object COMPONENT on the environment (after the
878binding of ucw:component) so that slots are, by default,
879visable."</span>
880 (make-standard-environment `((component . ,component)) component))
881
7404d4e1 882(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">render</span> ((component template-component))
883 <span class="emacs-face-string">"Render a template based component.
2aff8b5c 884
885Calls the component's template. The name of the template is the
886value returned by the generic function
887template-component.template-name, the template will be rendered
888in the environment returned by the generic function
889template-component-environment."</span>
890 (render-template *context*
891 (template-component.template-name component)
892 (template-component-environment component)))
893
894</pre>
895
896<p>Subclass and override methods. <code>simple-template-component</code> only provides
897the ability to set environment variables in initarg. Subclass to
898provide automagic template file name generation and such.</p>
899
900
901<h4><a name="sec13" id="sec13"></a>
902Utility Mixin Components</h4>
903
904<h5>Range View</h5>
905
906<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/range-view.lisp">src/components/range-view.lisp</a></p>
907
908<pre class="src">
7404d4e1 909(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">range-view</span> (template-component)
910 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:template-name</span> <span class="emacs-face-string">"ucw/range-view.tal"</span>)
911 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Component for showing the user a set of data one \"window\" at a time.
2aff8b5c 912
913The data set is presented one \"window\" at a time with links to
914the the first, previous, next and last window. Each window shows
915at most WINDOW-SIZE elements of the data. The data is passed to
916the range-view at instance creation time via the :DATA initarg.
917
918The generic function RENDER-RANGE-VIEW-ITEM is used to render
919each item of DATA.
920
921In order to change the rendering of the single elements of a
922range view developer's should create a sub class of RANGE-VIEW
923and define their RENDER-RANGE-VIEW-ITEM methods on that."</span>)
7404d4e1 924 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 925</pre>
926
927<pre class="src">
7404d4e1 928(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">render-range-view-item</span> (range-view item)
929 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Render a single element of a range-view."</span>)
930 (<span class="emacs-face-builtin">:method</span> ((range-view range-view) (item t))
931 <span class="emacs-face-string">"Standard implementation of RENDER-RANGE-VIEW-ITEM. Simply
2aff8b5c 932applies ITEM to princ (via &lt;:as-html)."</span>
7404d4e1 933 (<span class="emacs-face-keyword">declare</span> (ignore range-view))
2aff8b5c 934 (&lt;:as-html item)))
935</pre>
936
937
938<h5>Widget</h5>
939
940<p>Mixin with existing component to wrap in a div or span. This is handy
941for defining lightweight widgets embedded within other components.</p>
942
943<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/html-element.lisp">src/components/html-element.lisp</a></p>
944
945<pre class="src">
7404d4e1 946(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">html-element</span> (component)
2aff8b5c 947 ((css-class)
948 (dom-id)
949 (css-style)
950 (extra-tags)
951 (events))
7404d4e1 952 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"An HTML element.
2aff8b5c 953
954HTML elements control aspects that are relevant to almost all tags.
955
956Firstly they provide a place to store the class, id, and style of the
957component. The specific render methods of the components themselves
958must pass these values to whatever code is used to render the actual
959tag.
960
961Secondly, they allow javascript event handlers to be registered for a
962tag. The events slot can be filled with a list of lists in the form
963
964 (event parenscript-statement*)
965
966For example (\"onclick\" (alert \"You clicked!\") (return nil)). If
967the element has a dom-id, these event handlers are automatically
968added."</span>))
969</pre>
970
971<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/widget.lisp">src/components/widget.lisp</a></p>
972
973<pre class="src">
7404d4e1 974(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">widget-component</span> (html-element)
2aff8b5c 975 ()
7404d4e1 976 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"A widget which should be wrapped in a &lt;div&gt;."</span>))
2aff8b5c 977
7404d4e1 978(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">inline-widget-component</span> (html-element)
2aff8b5c 979 ()
7404d4e1 980 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"A widget which should be wrapped in &lt;span&gt; and not &lt;div&gt;"</span>))
2aff8b5c 981
7404d4e1 982(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">render</span> <span class="emacs-face-builtin">:wrap-around</span> ((widget widget-component)))
983(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">render</span> <span class="emacs-face-builtin">:wrap-around</span> ((widget inline-widget-component)))
2aff8b5c 984</pre>
985
986
987<h5>Transactions</h5>
988
989<p>A mixin to provide transactions. <code>(open-transaction component)</code> and
990<code>(close-transaction component)</code> open and closed nested
991transactions. After a transaction has been closed an attempt to
992backtrack into a step inside the transaction will result in jumping up
993one level of transactions (or out of the transaction entirely if at
994the top level). This ensures that the transaction is only run once,
995naturally.</p>
996
997<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/transaction-mixin.lisp">src/components/transaction-mixin.lisp</a></p>
998
999<pre class="src">
1000(defcomponent transaction-mixin ()
1001 (...))
1002
1003(defmethod/cc open-transaction ((comp transaction-mixin)))
1004(defmethod/cc close-transaction ((comp transaction-mixin)))
1005</pre>
1006
1007
1008<h5>Task</h5>
1009
1010<p><code>(defaction start ...)</code> on subclass to run a series of actions bundled
1011into a task.</p>
1012
1013<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/task.lisp">src/components/task.lisp</a></p>
1014
1015<pre class="src">
7404d4e1 1016(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">task-component</span> (standard-component)
2aff8b5c 1017 (...)
7404d4e1 1018 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"A controller for a single task or operation to
2aff8b5c 1019 be performed by the user.
1020
1021 A task component's START action is called as soon as the
1022component is instantiated. Task components do not have their own
1023RENDER method, in fact they have no graphical representation but
1024serve only to order a sequence of other components."</span>))
1025
1026(defgeneric/cc start (task)
7404d4e1 1027 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"action which gets called automatically when
2aff8b5c 1028task-component is active. Use defaction to define your own
1029\"start\" action"</span>))
1030</pre>
1031
1032
1033<h5>Cached</h5>
1034
1035<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/cached.lisp">src/components/cached.lisp</a></p>
1036
1037<pre class="src">
1038(defcomponent cached-component ()
7404d4e1 1039 ((cached-output <span class="emacs-face-builtin">:accessor</span> cached-output <span class="emacs-face-builtin">:initform</span> nil
1040 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"A string holding the output to
2aff8b5c 1041 use for this component. This string will be
1042 written directly to the html stream and is
1043 changed by the REFRESH-COMPONENT-OUTPUT
1044 method."</span> )
7404d4e1 1045 (timeout <span class="emacs-face-builtin">:accessor</span> timeout <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:timeout</span>
1046 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"An value specifying how often this
2aff8b5c 1047 component needs to be refreshed. The exact
1048 interpretation of the value depends on the type of
1049 caching used class."</span>))
7404d4e1 1050 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Component which caches its output.
2aff8b5c 1051
1052The component caching API is built around the generic functions
1053COMPONENT-DIRTY-P and REFRESH-COMPONENT-OUTPUT and a method on
1054RENDER, see the respective docstrings for more details.
1055
1056Do not use CACHED-COMPONENT directly, use one its subclasses."</span>))
1057
7404d4e1 1058(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">component-dirty-p</span> (component)
1059 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Returns T is COMPONENT's cache is invalid."</span>))
2aff8b5c 1060
7404d4e1 1061(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">update-cache</span> (component)
1062 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Update COMPONENT's cache variables after a refresh."</span>))
2aff8b5c 1063
1064(defcomponent timeout-cache-component (cached-component)
7404d4e1 1065 ((last-refresh <span class="emacs-face-builtin">:accessor</span> last-refresh <span class="emacs-face-builtin">:initform</span> nil
1066 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"The time, exrpessed as a
2aff8b5c 1067 universal time, when the component was last rendered."</span>))
7404d4e1 1068 (<span class="emacs-face-builtin">:default-initargs</span>
1069 <span class="emacs-face-builtin">:timeout</span> (* 30 60 60))
1070 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Render the component at most every TIMEOUT seconds."</span>))
2aff8b5c 1071
1072(defcomponent num-hits-cache-component (cached-component)
7404d4e1 1073 ((hits-since-refresh <span class="emacs-face-builtin">:accessor</span> hits-since-refresh
1074 <span class="emacs-face-builtin">:initform</span> nil
1075 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Number of views since last refresh."</span>))
1076 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:timeout</span> 10)
1077 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Render the component every TIMEOUT views."</span>))
2aff8b5c 1078</pre>
1079
1080<p>Subclass and override <code>component-dirty-p</code> to do something useful
1081(e.g. flip mark bit when object being presented changes).</p>
1082
1083
1084
1085
1086<h3><a name="sec14" id="sec14"></a>
1087Control Flow</h3>
1088
1089<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-component/control-flow.lisp">src/rerl/standard-component/control-flow.lisp</a></p>
1090
1091<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-action.lisp">src/rerl/standard-action.lisp</a></p>
1092
1093<h4><a name="sec15" id="sec15"></a>
1094Calling</h4>
1095
1096<p class="first">Most of what you do in UCW will be calling components so this is a bit
1097important. Note that calling interrupts the current control flow so if
1098you want to render a component in place as part of another component
1099just call <code>render</code> on it instead.</p>
1100
1101<pre class="src">
7404d4e1 1102(<span class="emacs-face-keyword">defmacro</span> <span class="emacs-face-function-name">call</span> (component-type <span class="emacs-face-type">&amp;rest</span> component-init-args)
1103 <span class="emacs-face-doc">"Stop the execution of the current action and pass control to
2aff8b5c 1104a freshly created component of type COMPONENT-TYPE.
1105
1106COMPONENT-INIT-ARGS are passed directly to the underlying
1107make-instance call. This form will return if and when the call'd
1108component calls answer, the value returned by this form is
1109whatever the call'd component passed to answer.
1110
1111Notes:
1112
1113This macro assumes that the lexcial variable UCW:SELF is bound to
1114the calling component."</span>)
1115
7404d4e1 1116(answer VAL) <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">answer parent component ONLY IN ACTIONS
2aff8b5c 1117</span>
7404d4e1 1118(ok SELF VAL) <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">Used to answer a component anywhere and what answer
1119</span> <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">expands into
2aff8b5c 1120</span>
7404d4e1 1121(jump COMPONENT-NAME <span class="emacs-face-type">&amp;REST</span> ARGS) <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">is similar to call, but replaces
1122</span> <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">the current component with the new
1123</span> <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">one and drops any backtracks (back
1124</span> <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">button will no longer work)
2aff8b5c 1125</span></pre>
1126
1127<p><code>(call COMPONENT-NAME &amp;ARGS INIT-ARGS)</code> calls <code>COMPONENT-NAME</code> and returns
1128the value returned by <code>(ok SELF RETURN-VALUE)</code> called from within
1129<code>COMPONENT-NAME</code></p>
1130
1131
1132<h4><a name="sec16" id="sec16"></a>
1133Actions</h4>
1134
1135<p class="first">Actions are methods on components. The first argument <strong>must</strong> be a
1136component for most of UCW to work.</p>
1137
1138<pre class="src">
1139(defaction NAME (first ...) ...)
7404d4e1 1140 <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">(roughly) expands into
2aff8b5c 1141</span>(defmethod/cc NAME (first ...)
7404d4e1 1142 (<span class="emacs-face-keyword">let</span> ((self first))
2aff8b5c 1143 ...))
1144</pre>
1145
1146<p><code>Self</code> being bound in the current lexical environment is required for
1147most UCW control flow things to work. <code>defaction</code> hides this from you,
1148and was a big source of confusion for me early on (mostly &quot;hmm, why is
1149this not working ... where did that come from in the
1150macroexpansion!&quot;).</p>
1151
1152
1153<h4><a name="sec17" id="sec17"></a>
1154Entry Points</h4>
1155
1156<pre class="src">
7404d4e1 1157(defentry-point url (<span class="emacs-face-builtin">:application</span> APPLICATION
1158 <span class="emacs-face-builtin">:class</span> DISPATCHER-CLASS)
1159 (PARAM1 ... PARAMN) <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">GET / POST vars, bound in body
2aff8b5c 1160</span> body)
1161</pre>
1162
1163<p>An entry point is what it sounds like: a static URL matched using the
1164mater of <code>DISPATCHER-CLASS</code> that enters into <code>APPLICATION</code> running the
1165code in <code>body</code>. An example from a test program I have written
1166follows. The entry point allows files to be streamed to user when the
1167url audio.ucw?file=FOO is used.</p>
1168
1169<pre class="src">
7404d4e1 1170(defentry-point <span class="emacs-face-string">"^(audio.ucw|)$"</span> (<span class="emacs-face-builtin">:application</span> *golf-test-app*
1171 <span class="emacs-face-builtin">:class</span> regexp-dispatcher)
2aff8b5c 1172 (file)
1173 (call 'audio-file-window
7404d4e1 1174 <span class="emacs-face-builtin">:audio-file</span> (make-instance 'audio-file
1175 <span class="emacs-face-builtin">:type</span> <span class="emacs-face-builtin">:vorbis</span>
1176 <span class="emacs-face-builtin">:data</span> (file-&gt;bytes (open
2aff8b5c 1177 file
7404d4e1 1178 <span class="emacs-face-builtin">:element-type</span> 'unsigned-byte)))))
2aff8b5c 1179</pre>
1180
1181
1182
1183<h3><a name="sec18" id="sec18"></a>
1184Dispatching</h3>
1185
1186<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-dispatcher.lisp">src/rerl/standard-dispatcher.lisp</a></p>
1187
1188<pre class="src">
7404d4e1 1189(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">matcher-match</span> (matcher application context)
1190 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Abstract method for subclasses to implement a
2aff8b5c 1191matcher. This method would return multiple-values according to
1192matcher internal nature.
1193
1194No methods defined on this function may rebind *context*, nor
1195change CONTEXT's application. Only if the method matches the
1196request, it is allowed to modify CONTEXT or APPLICATION, even in
1197that case methods defined on this function must not modify
1198CONTEXT's application nor rebind *context*."</span>))
1199
7404d4e1 1200(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">handler-handle</span> (handler application context matcher-result)
1201 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Abstract function for handler classes to
2aff8b5c 1202implement in order to handle a request matched by relevant
1203matcher.
1204
1205These methods may modify context as they wish since they'r
1206matched, request will be closed after this method is run."</span>))
1207
7404d4e1 1208(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">dispatch</span> (dispatcher application context)
1209 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"Entry point into a dispatcher. Must return T
2aff8b5c 1210 if the context has been handled or NIL if it hasn't.
1211
1212No methods defined on this function may rebind *context*, nor
1213change CONTEXT's application. Only if the method returns T is it
1214allowed to modify CONTEXT or APPLICATION, even in that case
1215methods defined on this function must not modify CONTEXT's
1216application nor rebind *context*."</span>))
1217</pre>
1218
1219<pre class="src">
7404d4e1 1220(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">my-matcher</span> (abstract-matcher) ...)
1221(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">my-handler</span> (abstract-handler) ...)
1222(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">my-dispatcher</span> (abstract-dispatcher my-matcher my-handler)
2aff8b5c 1223 ...)
1224</pre>
1225
1226<h4><a name="sec19" id="sec19"></a>
1227Simple Dispatcher</h4>
1228
1229<pre class="src">
7404d4e1 1230(<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-string">"This class of dispatchers avoids all of UCW's
2aff8b5c 1231 standard call/cc (and therefore frame/backtracking/component)
1232 mechanism.
1233
1234Unlike all other UCW dispatchers a simple-dispatcher must not use
1235CALL, and must perform the rendering directly within the handler."</span>)
1236</pre>
1237
1238
1239
1240<h3><a name="sec20" id="sec20"></a>
1241Server</h3>
1242
1243<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/control.lisp">src/control.lisp</a></p>
1244
1245<pre class="src">
7404d4e1 1246(<span class="emacs-face-keyword">defun</span> <span class="emacs-face-function-name">create-server</span> (<span class="emacs-face-type">&amp;key</span>
1247 (backend `(,*ucw-backend-type* <span class="emacs-face-builtin">:host</span> ,*ucw-backend-host*
1248 <span class="emacs-face-builtin">:port</span> ,*ucw-backend-port*))
2aff8b5c 1249 (applications *ucw-applications*)
1250 (start-p t)
1251 (server-class *ucw-server-class*)
1252 (log-root-directory (truename *ucw-log-root-directory*))
1253 (log-level *ucw-log-level*))
7404d4e1 1254 <span class="emacs-face-doc">"Creates and returns a UCW server according to SERVER-CLASS, HOST and
2aff8b5c 1255PORT. Affects *DEFAULT-SERVER*.
1256
1257BACKEND is a list of (BACKEND-TYPE &amp;rest INITARGS). BACKEND-TYPE
1258may be :HTTPD, :MOD-LISP, :ASERVE, :ARANEIDA, an existing
1259backend, an existing UCW server backend or :DEFAULT in which case
1260it attempts to return a sane default from the UCW backends loaded
1261and available, or any other value for which a valid MAKE-BACKEND
1262method has been defined. INITARGS will be passed, unmodified, to
1263MAKE-BACKEND.
1264
1265APPLICATIONS is a list of defined applications to be loaded into the
1266server.
1267
1268Logs are generated in verbosity defined by LOG-LEVEL and directed to
1269LOG-ROOT-DIRECTORY if defined."</span>
1270 ...
7404d4e1 1271 server) <span class="emacs-face-comment-delimiter">; </span><span class="emacs-face-comment">return server, naturally
2aff8b5c 1272</span></pre>
1273
1274
1275<h3><a name="sec21" id="sec21"></a>
1276Debugging</h3>
1277
1278<h4><a name="sec22" id="sec22"></a>
1279Inspector</h4>
1280
1281<p><a href="/home/clinton/src/ucw/darcs/ucw_dev/src/components/ucw-inspector.lisp">/home/clinton/src/ucw/darcs/ucw_dev/src/components/ucw-inspector.lisp</a></p>
1282
1283<pre class="src">
1284(defaction call-inspector ((component component) datum)
7404d4e1 1285 <span class="emacs-face-string">"Call an inspector for DATUM on the component COMPONENT."</span>
1286 (call 'ucw-inspector <span class="emacs-face-builtin">:datum</span> datum))
2aff8b5c 1287</pre>
1288
1289
1290
1291
1292<h2><a name="sec23" id="sec23"></a>
1293Tips</h2>
1294
1295<h3><a name="sec24" id="sec24"></a>
1296Getting dojo to load</h3>
1297
1298<p class="first">I had some trouble getting dojo to work properly with UCW. The way
1299that the <code>:www-roots</code> option for an application works is a bit
1300confusing, and it is unforgiving if you mess the pathname up. A
1301directory <strong>must</strong> have a <code>/</code> at the end, and the directory you are serving
1302must also have the <code>/</code> (which is counterintuitive given the behavior of
1303most unix things that don't want the <code>/</code> at the end of the name).</p>
1304
1305<pre class="src">
7404d4e1 1306<span class="emacs-face-builtin">:www-roots</span> (list '(<span class="emacs-face-string">"dojo/"</span> .
1307 #P<span class="emacs-face-string">"/home/clinton/src/ucw/darcs/ucw_dev/wwwroot/dojo/"</span>))
2aff8b5c 1308</pre>
1309
1310
1311<h3><a name="sec25" id="sec25"></a>
1312Specials Bound During Rendering</h3>
1313
1314<p class="first">The current request context is bound to <code>ucw:*context*</code>, and the current
1315component is bound to <code>ucw:*current-component*</code> in the dynamic extent of
1316<code>render</code>.</p>
1317
1318
1319<h3><a name="sec26" id="sec26"></a>
1320Printing to the yaclml stream</h3>
1321
1322<p class="first">Occasionally it can be useful to do something like write a byte array
1323as an ascii string to the client. Inside of <code>render</code> the variable
1324<code>yaclml:*yaclml-stream*</code> is bound to the stream that you can write to if
1325you wish to have content interspersed with yaclml tags.</p>
1326
1327
1328
1329 <!-- Page published by Emacs Muse ends here -->
1330
1331 <p class="cke-buttons">
1332 <!-- validating badges, any browser, etc -->
1333 <a href="http://validator.w3.org/check/referer"><img
1334 src="http://www.w3.org/Icons/valid-xhtml10"
1335 alt="Valid XHTML 1.0!" /></a>
1336
1337 <a href="http://www.anybrowser.org/campaign/"><img
1338 src="img/buttons/w3c_ab.png" alt="[ Viewable With Any Browser
1339 ]" /></a>
1340
1341 <a href="http://www.debian.org/"><img
1342 src="img/buttons/debian.png" alt="[ Powered by Debian ]" /></a>
1343
1344 <a href="http://hcoop.net/">
1345 <img src="img/buttons/hcoop.png"
1346 alt="[ Hosted by HCoop]" />
1347 </a>
1348
1349 <a href="http://www.fsf.org/register_form?referrer=114">
1350 <img src="img/buttons/fsf_member.png"
1351 alt="[ FSF Associate Member ]" />
1352 </a>
1353 </p>
1354
7404d4e1 1355<p class="cke-footer">And did those feet in ancient times
1356Walk bare upon these lonely streets like mine?
1357Does God watch us from that penthouse high above
1358His children down below who live on air and love?
2aff8b5c 1359</p>
1360<p class="cke-timestamp">Last Modified:
1361 March 13, 2008</p>
1362 </body>
1363</html>