PageTemplate 2.1.5 → 2.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes +6 -3
- data/Rakefile +1 -1
- data/lib/PageTemplate/parser.rb +9 -2
- data/test.rb +11 -0
- metadata +1 -28
- data/site/Makefile +0 -15
- data/site/MySubpageRenderer.rb +0 -43
- data/site/PageNavRenderer.rb +0 -37
- data/site/RedClothRenderer.rb +0 -20
- data/site/Site.rb +0 -11
- data/site/SiteNewsRenderer.rb +0 -23
- data/site/XhtmlTemplateRenderer.rb +0 -141
- data/site/base.css +0 -4
- data/site/footer.txt +0 -2
- data/site/header.txt +0 -2
- data/site/html/SiteMap.html +0 -43
- data/site/html/base.css +0 -4
- data/site/html/designer.html +0 -524
- data/site/html/index.html +0 -267
- data/site/html/install.html +0 -125
- data/site/html/programmer.html +0 -289
- data/site/html/version2.html +0 -103
- data/site/src/SiteMap +0 -8
- data/site/src/designer +0 -410
- data/site/src/index +0 -165
- data/site/src/install +0 -80
- data/site/src/metadata.txt +0 -4
- data/site/src/programmer +0 -235
- data/site/src/version2 +0 -59
data/site/html/version2.html
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
|
2
|
-
<title>PageTemplate Version 2: What's New?</title>
|
3
|
-
<link rel="STYLESHEET" href="base.css" type="text/css" title="base.css">
|
4
|
-
</head>
|
5
|
-
<body>
|
6
|
-
<h1>Yo!</h1>
|
7
|
-
<hr />
|
8
|
-
<p class="navbar">
|
9
|
-
<a href="SiteMap.html">Sitemap</a> || <a href="index.html">PageTemplate</a>
|
10
|
-
/ PageTemplate Version 2</p>
|
11
|
-
<h1>PageTemplate Version 2</h1>
|
12
|
-
<h2>What's New?</h2>
|
13
|
-
<hr />
|
14
|
-
|
15
|
-
<table width='100%' border='0'><tr>
|
16
|
-
<td><p><- <a href='programmer.html'>The Programmer’s Perspective</a></p>
|
17
|
-
</td>
|
18
|
-
<td align='right'><p><a href='SiteMap.html'>SiteMap</a>- ></p>
|
19
|
-
</td>
|
20
|
-
</tr></table>
|
21
|
-
|
22
|
-
<p>Thanks largely to Greg Millam there is a new release of PageTemplate.
|
23
|
-
Thanks entirely to Greg Millam, it is a complete revamping of PT’s
|
24
|
-
internal workings. While the basics of using PageTemplate as covered
|
25
|
-
by the other pages on this site are pretty much the same, a few things
|
26
|
-
have been added.</p>
|
27
|
-
|
28
|
-
|
29
|
-
<h2>New Features</h2>
|
30
|
-
|
31
|
-
|
32
|
-
<h3>The Preprocessor</h3>
|
33
|
-
|
34
|
-
|
35
|
-
<h4><code>reverse</code></h4>
|
36
|
-
|
37
|
-
|
38
|
-
<p>Amaze your friends! Baffle your enemies! Discover palindromes in your spare time!</p>
|
39
|
-
|
40
|
-
|
41
|
-
<p>This is a simple demonstration of the capabilities of PageTemplate’s preprocessor. It prints out the
|
42
|
-
reversed string of the value being displayed.</p>
|
43
|
-
|
44
|
-
|
45
|
-
<pre class="code">
|
46
|
-
Hello, [%var name%]. Your name spelled backwards is [%var name :reverse%].
|
47
|
-
</pre>
|
48
|
-
|
49
|
-
<pre class="sample">
|
50
|
-
Hello, Brian Wisti. Your name spelled backwards is itsiW nairB.
|
51
|
-
</pre>
|
52
|
-
|
53
|
-
<h4>escapeHTML</h4>
|
54
|
-
|
55
|
-
|
56
|
-
<pre class="code">
|
57
|
-
Here comes some sample HTML escaped.
|
58
|
-
|
59
|
-
[%var html :escapeHTML %]
|
60
|
-
</pre>
|
61
|
-
|
62
|
-
<p>Here comes some sample <span class="caps">HTML</span> escaped.</p>
|
63
|
-
|
64
|
-
|
65
|
-
<p><p><a href=’http://hack.your.email.ownzr.com/’>Update your <strong>PayPal</strong> account!</a></p></p>
|
66
|
-
|
67
|
-
|
68
|
-
<h4>escapeURI</h4>
|
69
|
-
|
70
|
-
|
71
|
-
<pre>[%var url :escapeURI %]</pre>
|
72
|
-
|
73
|
-
<p>And here’s a <span class="caps">URI</span>-escaped string. Isn’t the preprocessor great?</p>
|
74
|
-
|
75
|
-
|
76
|
-
<p>Brian+Wisti+%28contact+at+brianwisti%40rubyforge.org%29</p>
|
77
|
-
|
78
|
-
|
79
|
-
<h3>Case Directive</h3>
|
80
|
-
|
81
|
-
|
82
|
-
<h3>Object-style Variable Access</h3>
|
83
|
-
|
84
|
-
|
85
|
-
<h3>Handling Templates “On the Fly”</h3>
|
86
|
-
|
87
|
-
|
88
|
-
<h2>Fixed Problems</h2>
|
89
|
-
|
90
|
-
|
91
|
-
<h2>Additional Syntax</h2>
|
92
|
-
|
93
|
-
|
94
|
-
<h3>More stuff for <em>in</em></h3><hr />
|
95
|
-
|
96
|
-
<p class="navbar">
|
97
|
-
<a href="SiteMap.html">Sitemap</a> || <a href="index.html">PageTemplate</a>
|
98
|
-
/ PageTemplate Version 2</p>
|
99
|
-
|
100
|
-
<h1>Yo!</h1>
|
101
|
-
<hr />
|
102
|
-
</body>
|
103
|
-
</html>
|
data/site/src/SiteMap
DELETED
data/site/src/designer
DELETED
@@ -1,410 +0,0 @@
|
|
1
|
-
# 'title' = "The Designer's Perspective"
|
2
|
-
|
3
|
-
h2. Who Are You?
|
4
|
-
|
5
|
-
You are the esteemed Web Designer, aesthetically talented and
|
6
|
-
perhaps artistically inclined. You know what makes a good Web page.
|
7
|
-
You are not a programmer, though. It's horrible when you have to go
|
8
|
-
down to the caves where they keep the developers to explain
|
9
|
-
where a simple login form belongs. You also don't want to
|
10
|
-
remember where their odd-looking programming code is supposed to go
|
11
|
-
in your beautiful page. You want a simple, clean way of describing
|
12
|
-
the dynamic elements of site pages.
|
13
|
-
|
14
|
-
Okay, I've had too much coffee. This page explains how templating
|
15
|
-
works, and how to put PageTemplate to use when laying out the HTML
|
16
|
-
of your page.
|
17
|
-
|
18
|
-
h2. What's a Template?
|
19
|
-
|
20
|
-
When you are designing pages for a dynamic site or Web application,
|
21
|
-
there are a lot of details you won't know in advance. Some examples
|
22
|
-
might include login information, the contents of a shopping cart,
|
23
|
-
or maybe even the contents of the page! Templates
|
24
|
-
allow you to put placeholders within your HTML to show where that login
|
25
|
-
information is displayed and how it is formatted. A good template
|
26
|
-
system does not require you to remember code while you're designing:
|
27
|
-
you just make the page, and let programmers worry about filling it with
|
28
|
-
data.
|
29
|
-
|
30
|
-
In PageTemplate, those placeholders are referred to as _directives_.
|
31
|
-
|
32
|
-
h2. How Do I Use PageTemplate In My Pages?
|
33
|
-
|
34
|
-
PageTemplate uses a simple language which you can embed
|
35
|
-
in your page. You should be able to use your favorite design tools to
|
36
|
-
create an attractive template. My favorite design tool happens to be
|
37
|
-
"GNU/Emacs":/geekery/editors/emacs/index.html, but the odds are that
|
38
|
-
the designers out there lean towards something a little friendlier, like
|
39
|
-
"Macromedia Dreamweaver":http://www.dreamweaver.com/. With the default syntax,
|
40
|
-
all of us can be happy.
|
41
|
-
|
42
|
-
PageTemplate directives are indicated by being wrapped in between
|
43
|
-
@[%@ and @%]@ characters. If any of those characters are missing, PageTemplate
|
44
|
-
decides it is not a directive, and leaves it alone.
|
45
|
-
|
46
|
-
h3. Variables
|
47
|
-
|
48
|
-
The major directives require _variables_, which are just
|
49
|
-
names for the value your want inserted, checked, or otherwise
|
50
|
-
accessed. It's a good idea to use variable names that make
|
51
|
-
sense (@name@ for a person's name, @title@ for the title of the page, etc.).
|
52
|
-
|
53
|
-
h3. Value Substitution
|
54
|
-
|
55
|
-
Substitution is the easiest concept to master. When PageTemplate
|
56
|
-
comes across a value directive, it replaces that directive with some text.
|
57
|
-
|
58
|
-
h4. Syntax
|
59
|
-
|
60
|
-
<pre>
|
61
|
-
[%var variable %]
|
62
|
-
</pre>
|
63
|
-
|
64
|
-
h4. Example
|
65
|
-
|
66
|
-
<pre>
|
67
|
-
<h1>Hello, [%var name %]</h1>
|
68
|
-
</pre>
|
69
|
-
|
70
|
-
Every time that PageTemplate sees @[%var name %]@ in
|
71
|
-
your template, it will replace that directive with the text
|
72
|
-
associated with @name@.
|
73
|
-
|
74
|
-
The programmer works his magic, and the visitor "Frank" sees this
|
75
|
-
greeting:
|
76
|
-
|
77
|
-
<pre><h1>Hello, Frank</h1></pre>
|
78
|
-
|
79
|
-
If @name@ is not set, nothing is inserted. The greeting header would end up
|
80
|
-
looking like this:
|
81
|
-
|
82
|
-
<pre><h1>Hello, </h1></pre>
|
83
|
-
|
84
|
-
h3. If
|
85
|
-
|
86
|
-
The @if@ directive tells PageTemplate to only display a chunk of content when
|
87
|
-
some condition is true. If the condition is not true, PageTemplate skips the
|
88
|
-
block and moves on.
|
89
|
-
|
90
|
-
h4. Syntax
|
91
|
-
|
92
|
-
<pre>
|
93
|
-
[%if condition %]
|
94
|
-
chunk
|
95
|
-
[%endif%]
|
96
|
-
</pre>
|
97
|
-
|
98
|
-
h4. Example
|
99
|
-
|
100
|
-
<pre>
|
101
|
-
[%if pageowner%]
|
102
|
-
<a href="admin.cgi">Admin</a>
|
103
|
-
[%endif%]
|
104
|
-
</pre>
|
105
|
-
|
106
|
-
In this example, if the application tells PageTemplate that
|
107
|
-
@pageowner@ is true, PageTemplate inserts a link to
|
108
|
-
an administrative page. Otherwise, nothing happens here.
|
109
|
-
|
110
|
-
h3. If/Else
|
111
|
-
|
112
|
-
The @else@ directive adds extra power to @if@, by indicating a chunk of
|
113
|
-
content to use when a condition is not true.
|
114
|
-
|
115
|
-
h4. Syntax
|
116
|
-
|
117
|
-
<pre>
|
118
|
-
[%if value%]
|
119
|
-
chunk
|
120
|
-
[%else%]
|
121
|
-
alternate chunk
|
122
|
-
[%endif%]
|
123
|
-
</pre>
|
124
|
-
|
125
|
-
h4. Example
|
126
|
-
|
127
|
-
<pre>
|
128
|
-
[%if login%]
|
129
|
-
<p>Welcome back, [%var login%]!</p>
|
130
|
-
<p><a href="logout.cgi">Log Out</a></p>
|
131
|
-
[%else%]
|
132
|
-
<form name="login" method="post">
|
133
|
-
Login: <input type="text" name="login" /><br />
|
134
|
-
Password: <input type="password" name="passwd" /><br />
|
135
|
-
<input type="submit" value="Login" />
|
136
|
-
[%endif%]
|
137
|
-
</pre>
|
138
|
-
|
139
|
-
This is the situation where I use @else@ directives the
|
140
|
-
most. If the visitor is logged in to a Web application, she
|
141
|
-
is shown a brief welcoming message. If not, then she will see a
|
142
|
-
login form.
|
143
|
-
|
144
|
-
This example also shows a convenient approach to @if@
|
145
|
-
conditions. We _could_ make up a special @logged_in@
|
146
|
-
variable, but since all we care about here is the presence of a login,
|
147
|
-
we have PageTemplate test that as if it were a regular condition.
|
148
|
-
|
149
|
-
h3. Unless
|
150
|
-
|
151
|
-
Sometimes you only want to display a chunk if something is false, but
|
152
|
-
nothing if the condition is true. That description twisted my brain
|
153
|
-
a little bit. Think of it this way. Sometimes it's just easier to say
|
154
|
-
"unless something" instead of "if not_something". That's all. Templates
|
155
|
-
should be easy to read, you know? That's what this directive is for:
|
156
|
-
making some of the logic in your template easier to read.
|
157
|
-
|
158
|
-
h4. Syntax
|
159
|
-
|
160
|
-
<pre>
|
161
|
-
[%unless condition %]
|
162
|
-
chunk
|
163
|
-
[%end unless%]
|
164
|
-
</pre>
|
165
|
-
|
166
|
-
h4. Example
|
167
|
-
|
168
|
-
<pre>
|
169
|
-
[%unless launched%]
|
170
|
-
Product Launch Coming Soon!
|
171
|
-
[%end unless%]
|
172
|
-
</pre>
|
173
|
-
|
174
|
-
h3. In
|
175
|
-
|
176
|
-
Use the @in@ directive when you want PageTempate to insert the same chunk
|
177
|
-
repeatedly for a list of items. It can grab values from the item to be
|
178
|
-
inserted in @value@ directives within the chunk. If there is no list of items,
|
179
|
-
the @in@ chunk is skipped.
|
180
|
-
|
181
|
-
The @in@ directive is the most complex, and requires more explanation of its
|
182
|
-
details.
|
183
|
-
|
184
|
-
h4. Syntax
|
185
|
-
|
186
|
-
<pre>
|
187
|
-
[%in list%]
|
188
|
-
some text and [%var value%]
|
189
|
-
[%end in%]
|
190
|
-
</pre>
|
191
|
-
|
192
|
-
h4. Example
|
193
|
-
|
194
|
-
<pre>
|
195
|
-
<ul>
|
196
|
-
[%in books%]
|
197
|
-
<li>"[%var title%]" by [%var author%]</li>
|
198
|
-
[%end in%]
|
199
|
-
</ul>
|
200
|
-
</pre>
|
201
|
-
|
202
|
-
It presents a list of favorite albums, along with the band that produced it.
|
203
|
-
If there was no such list, then PageTemplate would not insert anything, and
|
204
|
-
we would be left with @<ul></ul>@ all by itself.
|
205
|
-
That's more than a little awkward from a designer's point of view, but
|
206
|
-
the @no@ directive presentd in a few moments helps us work around that.
|
207
|
-
|
208
|
-
h4. "Local" Values
|
209
|
-
|
210
|
-
When stepping through a list, PageTemplate works a little magic with
|
211
|
-
@value@ directives. First it examines the list item to see
|
212
|
-
if it has a value for the variable named. If it can't find one there,
|
213
|
-
it checks its main variable listing and tries to insert that. If it
|
214
|
-
can't find a value in the main variable listing, it inserts nothing for
|
215
|
-
that @value@ directive.
|
216
|
-
|
217
|
-
This logic works for nested lists, too. If you have an
|
218
|
-
<code>in</code> directive embedded in another <code>in</code> directive,
|
219
|
-
(say, a list of books written by each one of a list of your favorite
|
220
|
-
authors), PageTemplate first looks in the innermost list (the books) for
|
221
|
-
a name, then the next list out (the authors), and finally the main
|
222
|
-
variable listing.
|
223
|
-
|
224
|
-
h4. Loop Metavariables
|
225
|
-
|
226
|
-
_Metavariables_ were added in 1.2 so that you can fine-tune your lists, loops, and tables. They are special
|
227
|
-
flags that are set during certain times in a loop: the first time through, the last time through, during
|
228
|
-
odd trips through the loop, etcetera. Metavariables are uppercased and wrapped in double underscores to
|
229
|
-
emphasize that they are not normal variables.
|
230
|
-
|
231
|
-
Here are all of the metavariables that are defined in @in@ blocks.
|
232
|
-
|
233
|
-
|_. variable |_. description |
|
234
|
-
| @__FIRST__@ | true if this is the first time through the loop. |
|
235
|
-
| @__LAST__@ | true if this is the last time through the loop. |
|
236
|
-
| @__ODD__@ | true on odd-numbered steps through the loop (1st, 3rd, 5th) |
|
237
|
-
|
238
|
-
And to give a little idea of metavariables in action, here's a little example:
|
239
|
-
|
240
|
-
<pre>
|
241
|
-
<table>
|
242
|
-
<tr><th>#</th><th>Description</th><th>Amount</th></tr>
|
243
|
-
[%in transactions %]
|
244
|
-
[%if __ODD__ %]
|
245
|
-
<tr class="odd">
|
246
|
-
[%else%]
|
247
|
-
<tr>
|
248
|
-
[%endif%]
|
249
|
-
<td>[%var num%]</td>
|
250
|
-
<td>[%var description%]</td>
|
251
|
-
<td>[%var amount%]
|
252
|
-
</tr>
|
253
|
-
[%endin%]
|
254
|
-
</table>
|
255
|
-
</pre>
|
256
|
-
|
257
|
-
h3. In/No
|
258
|
-
|
259
|
-
The <code>no</code> directive allows you to use an alternate chunk
|
260
|
-
for an <code>in</code> if there is no list available.
|
261
|
-
|
262
|
-
h4. Syntax
|
263
|
-
|
264
|
-
<pre>
|
265
|
-
[%in list%]
|
266
|
-
[%var value%]
|
267
|
-
[%no%]
|
268
|
-
Nothing in the list
|
269
|
-
[%endin%]
|
270
|
-
</pre>
|
271
|
-
|
272
|
-
h4. Example
|
273
|
-
|
274
|
-
<pre>
|
275
|
-
<ul>
|
276
|
-
[%in books%]
|
277
|
-
<li>"[%var title%]" by [%var author%]</li>
|
278
|
-
[%no%]
|
279
|
-
<li>I have no favorites today.</li>
|
280
|
-
[%endin%]
|
281
|
-
</ul>
|
282
|
-
</pre>
|
283
|
-
|
284
|
-
This extends the earlier example by providing an alternate chunk
|
285
|
-
to use if there is no list named <code>books</code>. Now
|
286
|
-
the <acronym title="Hypertext Markup Language">HTML</acronym>
|
287
|
-
formatting is a little more appropriate. Instead of displaying
|
288
|
-
an empty list, it shows a list item declaring that there is no list.
|
289
|
-
|
290
|
-
I think I hurt my head with that last sentence.
|
291
|
-
|
292
|
-
h4. Lists and WYSIWYG Editors
|
293
|
-
|
294
|
-
Here's a specific problem that might pop up when you are using
|
295
|
-
a <acronym title="What You See Is What You Get">WYSIWYG</acronym>
|
296
|
-
editor. Let's say you're embedding a list into a table, so that each
|
297
|
-
item in the list gets one table row. Dreamweaver is probably not
|
298
|
-
going to like this style:
|
299
|
-
|
300
|
-
<pre>
|
301
|
-
<table>
|
302
|
-
[%in listing%]
|
303
|
-
<tr>
|
304
|
-
<td>[%var item%]</td>
|
305
|
-
</tr>
|
306
|
-
[%no%]
|
307
|
-
<tr>
|
308
|
-
<td>Listing is empty</td>
|
309
|
-
</tr>
|
310
|
-
[%endin%]
|
311
|
-
</table>
|
312
|
-
</pre>
|
313
|
-
|
314
|
-
The problem is that the <code>in listing</code>, <code>no</code>,
|
315
|
-
and <code>endin</code> directives are in locations that make for
|
316
|
-
invalid HTML, and might not be allowed by your editor.
|
317
|
-
|
318
|
-
It turns out that the solution is simple, though maybe a little
|
319
|
-
awkward. Wrap the offending directives in HTML comments, like this
|
320
|
-
example shows:
|
321
|
-
|
322
|
-
<pre>
|
323
|
-
<table>
|
324
|
-
<!-- [%in listing%] -->
|
325
|
-
<tr>
|
326
|
-
<td>[%var item%]</td>
|
327
|
-
</tr>
|
328
|
-
<!-- [%no%] -->
|
329
|
-
<tr>
|
330
|
-
<td>Listing is empty</td>
|
331
|
-
</tr>
|
332
|
-
<!-- [%endin%] -->
|
333
|
-
</table>
|
334
|
-
</pre>
|
335
|
-
|
336
|
-
Your fancy editor should be able to handle this, and PageTemplate
|
337
|
-
should be able to understand it just fine. The only side effect
|
338
|
-
is that you will have some empty comments in your final page.
|
339
|
-
|
340
|
-
The other solution is to use "Vim":/geekery/editors/vim/index.html,
|
341
|
-
"XEmacs":http://www.xemacs.org/, or some other effective
|
342
|
-
non-<acronym title="What You See Is What You Get">WYSIWYG</acronym>
|
343
|
-
editor. Personal preference, of course. I know that Dreamweaver and GoLive
|
344
|
-
cost good money, and you aren't going to toss them aside just because I say
|
345
|
-
so. Hopefully this workaround will suit your needs.
|
346
|
-
|
347
|
-
h3. Include
|
348
|
-
|
349
|
-
The @include@ directive is very simple to use, but it gives you a whole lot of
|
350
|
-
extra power. It allows you to include content that comes from another
|
351
|
-
files, including templates. This can be useful when building a page out of
|
352
|
-
smaller component templates.
|
353
|
-
|
354
|
-
h4. Syntax
|
355
|
-
|
356
|
-
<pre>[%include filename %]</pre>
|
357
|
-
|
358
|
-
@filename@ can point to a real file in a particular directory, or it could be a
|
359
|
-
placeholder variable name. If PageTemplate can't find that file, it displays a simple message stating
|
360
|
-
that the file was not found. The idea for this is to make it easier for developers to debug problems during
|
361
|
-
testing, rather than for you to wonder why there's a blank space where your menu text should be.
|
362
|
-
|
363
|
-
h4. Example
|
364
|
-
|
365
|
-
<pre>
|
366
|
-
[%include menu %]
|
367
|
-
</pre>
|
368
|
-
|
369
|
-
Meanwhile, we have something like this in <em>menu.txt</em>
|
370
|
-
|
371
|
-
<pre>
|
372
|
-
<table>
|
373
|
-
[%in photos%]
|
374
|
-
<tr>
|
375
|
-
<td>[%var title%]</td>
|
376
|
-
<td>[%var thumbnail %]</td>
|
377
|
-
</tr>
|
378
|
-
[%endin%]
|
379
|
-
</table>
|
380
|
-
</pre>
|
381
|
-
|
382
|
-
Do you see what I meant when I said "simple"? If not, then please let me know.
|
383
|
-
I'm still working on this part of the manual.
|
384
|
-
|
385
|
-
h3. Comments
|
386
|
-
|
387
|
-
Every once in a while you want to make a comment about your template, but not have it show up the
|
388
|
-
HTML markup that goes to the visitor. Comments are perfect for that. They are eaten up and spit aside
|
389
|
-
by PageTemplate when reading your template file, and the visitor never sees them.
|
390
|
-
|
391
|
-
h4. Syntax
|
392
|
-
|
393
|
-
<pre>
|
394
|
-
[%-- comment --%]
|
395
|
-
</pre>
|
396
|
-
|
397
|
-
h2. Customized Syntax
|
398
|
-
|
399
|
-
One of PageTemplate's features is the ability to come up with your
|
400
|
-
own directive syntax. If you feel that the default syntax is
|
401
|
-
less than ideal, discuss a new system with your developers. If
|
402
|
-
you are the lone designer/developer, talk to yourself for a bit. We
|
403
|
-
all need some quality time to ourselves occasionally. Working together,
|
404
|
-
you and the developers <em>(or you and your split personalities)</em>
|
405
|
-
can come up with a syntax that is much more comfortable.
|
406
|
-
|
407
|
-
h2. Conclusion
|
408
|
-
|
409
|
-
Yes, we've already reached the end of this designer's tutorial.
|
410
|
-
Now go make with the pretty pages!
|