All commands, alphabetic order; letter T

This page contains the description of the following commands tagbody, tag, tailp, tan, tanh, terpri, test_array_element, test-re-open, throw, time, timing, to_circle, topseq, trace, traceval, trace_handler, trace_one, truecomplexp, truncate, tyback, tycn, tynewline, type, typecn, typefn, type-of, typevector,

(tagbody b1 ... bn) (Lisp special form)

The tagbody command takes an arbitrary number of arguments. The return value is always (). The special form evaluates in sequence b1, b2, b3, etc. If one of these objects is a symbol it is not evaluated, but considered as a tag name. You can say (go foo), provided that foo is one of these tag names. In this case, execution resumes at this point. If the label appears more than once in the list, the first instance is selected, but this behavior might change in a future release.

[Endymion] (go)
go : wrong number of arguments : 0 this should be 1
[Endymion] (go 'foo)
go : undefined escape : 'foo
[Endymion] (go foo)
go : undefined escape : foo
[Endymion] (tagbody (go a) (car 0) a)
()
[Endymion] (tagbody (setq x 1) (go a) (setq x 2) a (setq y 3))
()
[Endymion] (list x y)
(1 3)
[Endymion] (tagbody (setq x 3) (go a) a (setq x 4) a (setq y 3))
()
[Endymion] x
4

Here is a non trivial example that shows that you can do loops, using if and go. We show two versions of the example. In one example, the go is hidden in a function. You can look at this page for a full trace.

[Endymion] (let ((n 5) l) (tagbody
[Endymion] tour (if (<= n 0) (go magne) (newl l (decr n)) (go tour))
[Endymion] magne) l)
(0 1 2 3 4)
[Endymion] (defun test (x)
[Endymion]  (newl xl x)
[Endymion]  (if (<= n 0) (go magne) (newl l (decr n)) (go tour)))
test
[Endymion] (setq xl ())
()
[Endymion] (let ((n 5) l) (tagbody tour (test n) magne) l)
(0 1 2 3 4)
[Endymion] (traceval (tagbody a 1 b 2 c 3 (go d)))
--> (tagbody a 1 b 2 c 3 (go d))
--> (go d)
find goto d failed: a b c
go : undefined escape : d
Throw to: error-tag ok 0

(tag tagname b1 ... bn) (Lisp special form)

The tag special form takes at least two arguments. The first argument has to be a symbol. It is not evaluated. The special form evtag behaves like tag but evaluates the first argument. Remaining arguments are evaluated as in progn. The return value of tag is the return value of the last argument. However, tag establishes a handler for exit. If (exit foo bar) is evaluated, and if the first argument of exit is the current tag name, then the value of bar will be the return value of tag.

[Endymion] (tag)
tag : wrong number of arguments : 0 this should be at least 2
[Endymion] (exit)
exit : wrong number of arguments : 0 this should be at least 2
[Endymion] (tag 1 2)
tag : not a symbol : 1
[Endymion] (exit 1 2)
exit : not a symbol : 1
[Endymion] (defun f1 () (exit foo (print 1) 11) 12)
f1
[Endymion] (defun f2 () (exit bar (print 1) 11) 12)
f2
[Endymion] (defun f3 () (exit gee (print 1) 11) 12)
f3
[Endymion] (tag foo (tag bar (f1) (print 2)) (print 3))
1
11
[Endymion] (tag foo (tag bar (f2) (print 2)) (print 3))
1
3
3
[Endymion] (tag foo (tag bar (f3) (print 2)) (print 3))
exit : undefined escape : gee

Here is another example. It uses a recusive function. The exit special form is called if a result is found.

[Endymion] (defun search (l x) (tag found (f4 l x)))
search
[Endymion] (defun f4 (l x)
[Endymion] (cond ((eq l x) (exit found l))
[Endymion]       ((consp l) (f4 (car l) x) (f4 (cdr l) x))
[Endymion]       (true ())))
f4
[Endymion] (search '(1 2 (3 . 4) 5 6) 3)
3
[Endymion] (search '(1 2 (3 . 4) 5 6) 7)
()
[Endymion] (search '(1 2 (3 . 4) 5 6) 6)
6

(tailp x y) (Lisp function)

The tailp function takes two arguments. It returns the first one if this can be obtained by applying the cdr function a given number of times to the second one; it returns () otherwise. The function could be defined as

(defun tailp (x y)
   (cond ((atom y) ())
         ((eq x y) x)
         (true (tailp x (cdr y))))) 

Example

[Endymion] (tailp 'x 'x)
()
[Endymion] (tailp 'x '(1 . x))
()
[Endymion] (setq l '(a b c d) l1 (cddr l))
(c d)
[Endymion] (tailp l1 l)
(c d)
[Endymion] (tailp '(c d) l)
()

(terpri f) (Lisp function)

The (terpri n) instruction terminates printing current expression. If the argument is a positive number N, then N newline characters are printed. If the argument is a negative number, nothing is printed. If the argument is omitted, or is not a number, a single new line is printed. The function returns true. For an example, see tycn.

test_array_element (a,x1,...,xn) (Symbolic function)

The function returns true if the array a has a value at positions (x1,...,xn). See also makearray for details.

(test-re-open f) (Lisp function)

This function tests whether the file f is opened for input and output. If the argument is not a symbol nor a string, or if the file is not opened, the return value is nil. Otherwise it is the channel number. See examples under openo. The function handles the case where a file has more than one name (for instance in the case of a symbolic link). Thus, if A is a symlink to B, B is opened as channel 17, then (test-re-open "A") returns 17.

throw (a, b, c) (Symbolic function)

This function throws to the tag a the value b. In case of trouble, the function c signals an error. See catch for how to catchs a throw.

(1)  throw(25,b,myfct);
myfct : unable to throw (value is b) : 25

(time x1 ... xn) (Lisp macro)

The time macro returns the time used for evaluating the other arguments. Its expansion is (let ((RT (runtime))) x1 ... xn (- (runtime) RT)), where RT is a new symbol.

[Endymion] (setq x '(time (list 1 2 3)))
(time (list 1 2 3))
[Endymion] (eval x)
0
[Endymion] x
((#:system:lambda 1 (#:system:runtime) (list 1 2 3) (- (runtime) #:system:
runtime)) (runtime))

timing(x1, ..., xn) (Symbolic macro)

This macro executes the body, and prints the time (via printtime) required by the computations, and returns the value of the last evaluation. The macro is defined by

timing([x])::=
    buildq(a=gensym,b=gensym,
        let(a=runtime(),let(b={splice(x)},printtime(a),b)));

Examples

(1)  f(n):= for i=1...n do if  #isprime(i) then dynamic(x)++;

(1)                             <FUNCTION: f>

(2) timing(x:=0, f (10000),x);
Time 0.47s. 

(2)                                  1229

(3) timing(x:=0, f (100000),x);
Time 4.71s. 

(3)                                  9592

topseq(x) (Symbolic function)

This function returns the head an of an initialised sequence. If the end of the sequence is reached, the function returns false instead. See makeseq for details.

(traceval x) (Lisp special form)

The traceval special form takes one argument, which is evaluated in verbose mode. For an example, see this page.

trace (x1,...,xn) (Symbolic macro)

The trace macro can be used to trace symbolic functions via the trace_one function. See compiler. See also examples below.

trace_handler(n, f1, f2, v, e, t) (Symbolic function)

This function is called whenever an object is traced. It may print something on the trace channel. The return value is false. Here e is a boolean, false on entry, true on exit, v is the value (on return). The quantity t is an integer (it may be a function of five arguments, returning an integer, cased where the function is called on n, f1 f2, v and e). This integer should be of the form 331 where the first digit concerns entry, the second exit, and the third the level. Let T be the digit that corresponds to e. This should be between 0 and 3. If zero, nothing is printed, if 1, the value of f1 if 2, the value of f2 is prnited, and if 3, the value of one of them is printed. The last digit should be 0 or 1. If 0, nothing happens. If Otherwise (level n) is printed with the message.

When you trace a function T is 2, and argument f2 should be a list, see example below, lines 1 to 3. Line 4 shows what is printed in the case of error. Lines 5 and 6 show an alternate syntax using f1. When you trace an array, T is 1, and argument f1 is used. Instead of the string "fun", the string array "should" be used. On exit, the second element in the list can be "size"=x, see exemple 7. In all other cases, it should be "indices"=[...], see lines 8 to 10.

(1) trace_handler(3,false,[f,a,b],12,false,330)?;
f(a, b) --> 
(2) trace_handler(3,false,[f,a,b],12,true,330)?;
f(a, b) --> 12
(3) trace_handler(3,false,[f,a,b],12,true,default)?;
(level 3) f(a, b) --> 12
(4) trace_handler(3,false,bad,12,true,221)?;
(level 3) bad_object = bad, result = 12
(5) trace_handler(3,["fun"=f,arg1=a,arg2=b],nil,12,false,all)?;
(level 3) f --> arg1 = a, arg2 = b
(6) trace_handler(3,["fun"=f,arg1=a,arg2=b],nil,12,true,all)?;
(level 3) f <-- arg1 = a, arg2 = b, result = 12
(7) trace_handler(3,["array"=f,"size"=10],nil,12,true,all)?;
(level 3) (array) f (resizing) 10 --> 12
(8) trace_handler(3,["array"=f,"indices"=[u,v]],nil,12,false,all)?;
(level 3) f     (computing) --> 
           u, v
(9) trace_handler(3,["array"=f,"indices"=[u,v]],nil,12,true,all)?;
(level 3) f     --> 12
           u, v
(10) trace_handler(3,["array"=f,"indices"=[u,v],"value"=4],nil,12,false,all)?;
(level 3) f     <-- 4
           u, v

Example of calls of trace. In this case, f is a hash array; this means that a vector of size N is used to store the data, where N is twice the square root of the number of elements of the array. Each element of this vector is called a bucket, it contains the list of all slots, with the same hash value modulo N. For each iteration in the loop (5), one line is printed, it is omitted here. However, we left the line that says that N changes from 8 to 14. On line 6, you can see that the array holds 30 elements, and the buckets have size 2 (and 3 in some cases). This is due to the fact that the hash value of a slot containg a small integer I has the form a+3*I.

(1) defarray(f,hash,int,all);

(1)                               <ARRAY: f>

(2) trace(f);

(2)                                  done

(3) f[1]:=2;
(level 0) f  <-- 2
           1

(3)                                   2

(4) f[1];
(level 0) f  --> 2
           1

(4)                                   2

(5) for i in 1...30 do f[i]:=i+1;

(level 0) (array) f (resizing) 8 --> 14
(5)                                  done

(6) array_info(f);

(6)           [1, 30, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2]

(7) define_array_function(f,n,f[n-1]+f[n-2]);

(7)                               <ARRAY: f>

(8) f[33];
(level 0) f   (computing) -->
           33
(level 1) f   (computing) -->
           32
(level 2) f   (computing) -->
           31
(level 3) f   --> 31
           30
(level 3) f   --> 30
           29
(level 3) f   <-- 61
           31
(level 3) f   --> 61
           31
(level 2) f   --> 31
           30
(level 2) f   <-- 92
           32
(level 2) f   --> 92
           32
(level 1) f   --> 61
           31
(level 1) f   <-- 153
           33
(level 1) f   --> 153
           33

(8)                                  153

trace_one(f,spec) (Symbolic function)

The effect of this command is to trace the object f. This modifies the behavior, for instance by calling the trace handler (see above) with some arguments: trace_handler(n, f1, f2, v, e, t) . The second argument should be a list or a set of specifications, of the form a=b; the LHS is one of entry, exit, level, simp, array, or fun. The default value is zero; if you say trace(foo), this sets all values to true, if you say untrace(foo), this sets all values to false.

If the LHS is entry, an integer between 0 and 3 is needed. Default is zero, false is zero, and everything but an integer in the range 0...3 is 3. Idem for exit. Idem for level, with 3 replaced by 1. These three integers are merged into an integer t . There are four cases for f; if this is a symbolic variable, it will be traced; this has currently no particularly interesting results. If is is Lisp symbol, the associated Lisp function will be traced, and a string will be converted to a Lisp symbol; this may succeed or not.

Assume that f is an array or a symbolic function; Let T be the value of array or fun, respectively. If this value is true, then t will be used instead. This will be the last argument of trace-handler, hence there are some restrictions. If T is false, zero, or one, the tracing propert of f will be removed. See example above of what happens when an array is traced. In the example below, we show what happens in the case of a function. Both quantities f1 and f2 are computed, and you can select one; note that the trace specification may specify a function for fun, hence for T. In the example that follows, we use it to discard the trace if the level is too high.

(1) fib(n):=if n<3 then 1 else fib(n-1)+ fib(n-2);

(1)                            <FUNCTION: fib>

(2) fib(10);

(2)                                   55

(3) trace(fib)?;

(4) fib(5);

(level 0) fib --> n = 5
(level 1) fib --> n = 4
(level 2) fib --> n = 3
(level 3) fib --> n = 2
(level 3) fib <-- n = 2, result = 1
(level 3) fib --> n = 1
(level 3) fib <-- n = 1, result = 1
(level 2) fib <-- n = 3, result = 2
(level 2) fib --> n = 2
(level 2) fib <-- n = 2, result = 1
(level 1) fib <-- n = 4, result = 3
(level 1) fib --> n = 3
(level 2) fib --> n = 2
(level 2) fib <-- n = 2, result = 1
(level 2) fib --> n = 1
(level 2) fib <-- n = 1, result = 1
(level 1) fib <-- n = 3, result = 2
(level 0) fib <-- n = 5, result = 5

(5) trace_one(fib,[fun=lambda([n,f1,f2,v,e],if n<3 then 221 else 0)])?;

(6) fib(10);

(level 0) fib(10) --> 
(level 1) fib(9) --> 
(level 2) fib(8) --> 
(level 2) fib(8) --> 21
(level 2) fib(7) --> 
(level 2) fib(7) --> 13
(level 1) fib(9) --> 34
(level 1) fib(8) --> 
(level 2) fib(7) --> 
(level 2) fib(7) --> 13
(level 2) fib(6) --> 
(level 2) fib(6) --> 8
(level 1) fib(8) --> 21
(level 0) fib(10) --> 55

(6)                                   55

(7) g([w]):=w?; f(x,y,[z]):=g(x,y,z)?;

(9) trace(f,g)?;

(10) f(1,2,3,4);

(level 0) f --> x = 1, y = 2, z = [3, 4]
(level 0) g --> w = [1, 2, [3, 4]]
(level 0) g --> w = [1, 2, [3, 4]], result = [1, 2, [3, 4]]
(level 0) f --> x = 1, y = 2, z = [3, 4], result = [1, 2, [3, 4]]

(10)                             [1, 2, [3, 4]]

(truecomplexp n) (Lisp function)

This function returns its argument if it is a true complex number and false otherwise. All numbers known to Endymion are complex, the function returns its argument if (type-of n) is complex. For an example see numberp.

(truncate x) (Lisp function)

Returns the integer par of x (truncation towards zero). See floor.

(tyback) (Lisp function)

The (tyback) function erases the previous character by printed a backspace, a space, and backspace. It returns nil. For an example, see tycn.

(tycn n) (Lisp function)

The (tycn 97) function call prints character with code 97 (lower case letter a) on the terminal, and returns the value of the character. Instead of 97, any integer between 0 and 255 is accepted. Characters are printed directly, not put in a buffer. In the example that follows, we use (flush) in order to flush the buffer containing `foo', then erase the second o, and replace it by O.

[Endymion] (progn (prin 'foo)(flush)(tyback)(tycn #/O)
[Endymion] (tynewline)(prin 'foO)(terpri))
foO
foO
true

(tynewline) (Lisp function)

The (tynewline) function prints carriage return and newline on the terminal. For an example, see tycn.

type (Keyword)

Inside the conditional part of a macro, you can use type(x), see the compiler.

(typecn char val) (Lisp function)

The typecn function returns the character type of the character char (if called with one argument) or modifies it. In this case, the value must be one of the following

[Endymion] (defun testread1 (x)
[Endymion]   (let ((a (typecn #/a)))
[Endymion]     (typecn #/a 1)(typecn #/b 2)
[Endymion]     (typecn #/u 4)(typecn #/v 5)(typecn #/w 6)
[Endymion]     (setq x (read-from-string x))
[Endymion]     (typecn #/a a)(typecn #/b a)    
[Endymion]     (typecn #/u a)(typecn #/v a)(typecn #/w a)
[Endymion]     x))
testread1
[Endymion] (defun testread2(x)
[Endymion]   (let ((a (typecn #/A)))
[Endymion]     (typecn #/A 8) (typecn #/B 11)(typecn #/C 13)
[Endymion]     (setq x (read-from-string x))
[Endymion]     (typecn #/A a)(typecn #/B a)(typecn #/C a)
[Endymion]     x))
testread2
[Endymion] (testread1 "uxavbyv")
(x y)
[Endymion] '("a\"b" a\( b 1\3)
(a"b a( b 13)
[Endymion] (testread1 "u1w3v")
(1w3)
[Endymion] (testread1 "u1 w 3v")
(1 . 3)
[Endymion] (explode (testread2 "B. B"))
(46 32)
[Endymion] (testread2 "(a C)(BCx)")
(a )(Bx)
[Endymion] (cadr (testread2 "(a C)(BCx)"))
)(Bx
[Endymion] (testread2 "aCbC|dD||eCCfCg")
abdD|eCfg
[Endymion] (testread2 "BbC""""dD||eBBfBg")
bC"dD||eBf

If a character has type 10, it is a macro. There are six predefined macros. You can define your own macros (see definition of W below). If you say !foo, all characters up to the end of the line are read, and the result is (comline "foo"). If you say 'foo, an expression is read (here foo), and the result is the same as (quote foo). If you say $foo, it is the same as #:endymion:foo. If you say #[], you create an empty vector (see below how sharp open-bracket are read); any other use of a closing bracket is an error. If you say `(foo ,bar), it is as if you has said (list 'foo bar). Some explanations are needed here. First a comma is invalid outside the scope of a backquote. Otherwise, a comma looks at the character that follows. If this character is a comma or an at-sign it is read. The expression that follows is read also. Once the backquote has read an expression E, it converts it into f(E) as follows. If E is nil, the result is nil; if E is not a list, the result is the same as if a single quote has been used. Thus `foo is the same as 'foo or (quote foo). Let A be the car of E. If A is a comma, the result is the cdr of E. Thus `,foo is the same as foo (but `,.foo and `,@foo are invalid). Let B be the cdr of E, and D be f(B). If A is a cons whose car is a comma, say ,foo, ,.foo or ,@foo then the result is (cons foo D), (nconc foo D) or (append foo D), respectively. Othewise, the result if the cons of f(A) and D. The actual result can be something whose evaluation is the same as what the previous rules would give. For instance `(,foo) is (cons foo nil), simplified to (list foo), see examples below.

[Endymion] (defun W() (let ((x (read))) (list x x)))
W
[Endymion] (typecn #/W 10) '(W (1 2) 3)
10
(((1 2) (1 2)) 3)
[Endymion] !pwd
/user/grimm/home/cvs/endymion/src
[Endymion] $foo
eval : undefined variable : #:endymion:foo
[Endymion] (read) `()
()
[Endymion] (read) `foo
'foo
[Endymion] (read) `,foo
foo
[Endymion] (read) `(,foo . ,bar)
(cons foo bar)
[Endymion] (read) `(,.foo . ,bar)
(nconc foo bar)
[Endymion] (read) `(,@foo . ,bar)
(append foo bar)
[Endymion] (read) `(,.foo  ,.bar .,gee)
(nconc foo (nconc bar gee))
[Endymion] (read) `(,@foo  ,@bar ,@gee)
(append foo bar gee)
[Endymion] (read) `(,@foo  ,@bar ,@gee x y)
(append foo bar gee '(x y))
[Endymion] (read) `(,foo  ,bar gee)
(mcons foo bar '(gee))

A character of type 9 is a splice character, by default it is the # character. The character C that follows is considered and some action depends on it. In a case like #:foo:bar, the character C is the colon, its effect is to read a symbol in the empty package. When the second colon is seen (a character of type 8) a second symbol is read. The result is then the symbol named `bar' in the package `foo'. In the case of #:foo:bar:gee, the result is a symbol named `gee' in the package #:foo:bar. In the case of :gee the result is a symbol named `gee' in the package whose value is in #:sys-package:colon (default is `user'). In the case of #:foo:12, the number 12 is read in the package foo, this is an error. Expressions like #:foo:(, #:foo:$ are equally wrong. In a case like #:foo:#X, the splice function associated to X is called, with the package `foo'. This may be valid or not. It is invalid if X is one of "\/.<()#'oU"$#=. You can say #25W, if this case, the function associated to W is called with 25 as argument. Unless otherwise specified, specifying a number is an error.

[Endymion] #:data:#[2000 1 31 3 4 5]
#:data:#[2000 1 31 3 4 5]
[Endymion] #:date:#[2000 1 31 3 4 5]
Mon Jan 31 2000 03:04:05
[Endymion] '(#\bs#\del#\dq#\esc#\tab#\semi#\null#\bell#\rubout#\return) 
(8 127 34 27 9 59 0 7 127 13)
[Endymion] '(#\sp #\cr #\lf#\lp#\rp)
(32 13 10 40 41)
[Endymion] (implode '(#/f #/o #/o))
foo
[Endymion] '#(1 #. 2 #)
(1 2)
[Endymion] ## Hey
[Endymion] #'foo
foo
[Endymion] '(10 20 #.(+ 10 20))
(10 20 30)
[Endymion] #<1235678098765432>
1312068668459734066
[Endymion] #16R1235678098765432
1312068668459734066
[Endymion] '(#Ué #"José" #.(concat #"José"))
(233 José José José)
[Endymion] '(#o100 #%100 #$100)
(64 4 256)
[Endymion] '(#o100/2 #%100/11 #$100/FF)
(32 4/3 256/255)
[Endymion] (defun #:|#|:W() (let ((x (read))) (list x x)))
#:#:W
[Endymion] '( 1 2 #W 3 4)
(1 2 3 3 4)
[Endymion] '(#Wa #12Wb #:foo:#Wc #:bar:#13W d)
((a a () ()) (b b 12 ()) (c c () foo) (d d 13 bar))
[Endymion] '(#10R10 #10R17/23 #22R17/23)
(10 17/23 29/47)

(typefn symbol) (Lisp function)

The typefn function takes as argument a symbol; it returns the functional type of the argument. It returns nil in the case where the argument is not a symbol, or if no function is associated to it. Example, showing all types of functions

[Endymion] (typefn 'version)
subr0
[Endymion] (typefn 'car)
subr1
[Endymion] (typefn 'symbol)
subr2
[Endymion] (typefn 'vset)
subr3
[Endymion] (typefn 'mset)
subr4
[Endymion] (typefn 'end)
subrv1
[Endymion] (typefn 'typevector)
subrv2
[Endymion] (typefn 'getfn)
subrv3
[Endymion] (typefn 'fillvector)
subrv4
[Endymion] (typefn 'list)
subrn
[Endymion] (typefn 'if)
fsubr
[Endymion] (typefn 'ifn)
dmsubr
[Endymion] (dmd mymac ())
mymac
[Endymion] (typefn 'mymac)
macro
[Endymion] (defun myfct ())
myfct
[Endymion] (typefn 'myfct)
expr
[Endymion] (typefn 'random-symbol)
()
[Endymion] (typefn '(lambda (x) x))
()

(type-of obj) (Lisp function)

The type-of function takes an object as argument and returns its type. Example

[Endymion] (type-of 10)
fix
[Endymion] (type-of 10.2)
float
[Endymion] (type-of '(foo))
cons
[Endymion] (type-of "(foo)")
string
[Endymion] (type-of #[])
vector
[Endymion] (type-of #:foo:bar:#[])
#:foo:bar
[Endymion] (type-of 'foo)
symbol
[Endymion] (type-of ())
null

(typevector vec type) (Lisp function)

The typector function takes one or two arguments. The first argument must be a vector, the second a symbol. In the case of one argument, the type of the vector is returned. In the case of two arguments, the type is changed to the second argument. The return value is the type.

[Endymion] (typevector)
typevector : wrong number of arguments : 0 this should be at least 1
[Endymion] (typevector 1 2 3)
typevector : wrong number of arguments : 3 this should be at most 2
[Endymion] (setq x #:foo:#[1 2 3])
#:foo:#[1 2 3]
[Endymion] (typevector x)
foo
[Endymion] (defun #:xfoo:prin (x) (prin "Xfoo"))
#:xfoo:prin
[Endymion] (typevector x 'xfoo)
xfoo
[Endymion] x
Xfoo
[Endymion] (typevector x 'xbar)
xbar
[Endymion] x
#:xbar:#[1 2 3]
[Endymion] (typevector x 12)
typevector : not a symbol : 12

Valid XHTML 1.0 Strict back to home page © INRIA 2005, 2006 Last modified $Date: 2009/01/08 17:43:30 $