anise 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING CHANGED
@@ -1,168 +1,166 @@
1
- .
1
+ = GNU LESSER GENERAL PUBLIC LICENSE
2
2
 
3
- GNU LESSER GENERAL PUBLIC LICENSE
4
- Version 3, 29 June 2007
3
+ <b>Version 3, 29 June 2007</b>
5
4
 
6
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
7
- Everyone is permitted to copy and distribute verbatim copies
8
- of this license document, but changing it is not allowed.
5
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
9
8
 
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
10
12
 
11
- This version of the GNU Lesser General Public License incorporates
12
- the terms and conditions of version 3 of the GNU General Public
13
- License, supplemented by the additional permissions listed below.
13
+ == 0. Additional Definitions.
14
14
 
15
- 0. Additional Definitions.
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
16
18
 
17
- As used herein, "this License" refers to version 3 of the GNU Lesser
18
- General Public License, and the "GNU GPL" refers to version 3 of the GNU
19
- General Public License.
20
-
21
- "The Library" refers to a covered work governed by this License,
22
- other than an Application or a Combined Work as defined below.
23
-
24
- An "Application" is any work that makes use of an interface provided
25
- by the Library, but which is not otherwise based on the Library.
26
- Defining a subclass of a class defined by the Library is deemed a mode
27
- of using an interface provided by the Library.
28
-
29
- A "Combined Work" is a work produced by combining or linking an
30
- Application with the Library. The particular version of the Library
31
- with which the Combined Work was made is also called the "Linked
32
- Version".
33
-
34
- The "Minimal Corresponding Source" for a Combined Work means the
35
- Corresponding Source for the Combined Work, excluding any source code
36
- for portions of the Combined Work that, considered in isolation, are
37
- based on the Application, and not on the Linked Version.
38
-
39
- The "Corresponding Application Code" for a Combined Work means the
40
- object code and/or source code for the Application, including any data
41
- and utility programs needed for reproducing the Combined Work from the
42
- Application, but excluding the System Libraries of the Combined Work.
43
-
44
- 1. Exception to Section 3 of the GNU GPL.
45
-
46
- You may convey a covered work under sections 3 and 4 of this License
47
- without being bound by section 3 of the GNU GPL.
48
-
49
- 2. Conveying Modified Versions.
50
-
51
- If you modify a copy of the Library, and, in your modifications, a
52
- facility refers to a function or data to be supplied by an Application
53
- that uses the facility (other than as an argument passed when the
54
- facility is invoked), then you may convey a copy of the modified
55
- version:
56
-
57
- a) under this License, provided that you make a good faith effort to
58
- ensure that, in the event an Application does not supply the
59
- function or data, the facility still operates, and performs
60
- whatever part of its purpose remains meaningful, or
61
-
62
- b) under the GNU GPL, with none of the additional permissions of
63
- this License applicable to that copy.
64
-
65
- 3. Object Code Incorporating Material from Library Header Files.
66
-
67
- The object code form of an Application may incorporate material from
68
- a header file that is part of the Library. You may convey such object
69
- code under terms of your choice, provided that, if the incorporated
70
- material is not limited to numerical parameters, data structure
71
- layouts and accessors, or small macros, inline functions and templates
72
- (ten or fewer lines in length), you do both of the following:
73
-
74
- a) Give prominent notice with each copy of the object code that the
75
- Library is used in it and that the Library and its use are
76
- covered by this License.
77
-
78
- b) Accompany the object code with a copy of the GNU GPL and this license
79
- document.
80
-
81
- 4. Combined Works.
82
-
83
- You may convey a Combined Work under terms of your choice that,
84
- taken together, effectively do not restrict modification of the
85
- portions of the Library contained in the Combined Work and reverse
86
- engineering for debugging such modifications, if you also do each of
87
- the following:
88
-
89
- a) Give prominent notice with each copy of the Combined Work that
90
- the Library is used in it and that the Library and its use are
91
- covered by this License.
92
-
93
- b) Accompany the Combined Work with a copy of the GNU GPL and this license
94
- document.
95
-
96
- c) For a Combined Work that displays copyright notices during
97
- execution, include the copyright notice for the Library among
98
- these notices, as well as a reference directing the user to the
99
- copies of the GNU GPL and this license document.
100
-
101
- d) Do one of the following:
102
-
103
- 0) Convey the Minimal Corresponding Source under the terms of this
104
- License, and the Corresponding Application Code in a form
105
- suitable for, and under terms that permit, the user to
106
- recombine or relink the Application with a modified version of
107
- the Linked Version to produce a modified Combined Work, in the
108
- manner specified by section 6 of the GNU GPL for conveying
109
- Corresponding Source.
110
-
111
- 1) Use a suitable shared library mechanism for linking with the
112
- Library. A suitable mechanism is one that (a) uses at run time
113
- a copy of the Library already present on the user's computer
114
- system, and (b) will operate properly with a modified version
115
- of the Library that is interface-compatible with the Linked
116
- Version.
117
-
118
- e) Provide Installation Information, but only if you would otherwise
119
- be required to provide such information under section 6 of the
120
- GNU GPL, and only to the extent that such information is
121
- necessary to install and execute a modified version of the
122
- Combined Work produced by recombining or relinking the
123
- Application with a modified version of the Linked Version. (If
124
- you use option 4d0, the Installation Information must accompany
125
- the Minimal Corresponding Source and Corresponding Application
126
- Code. If you use option 4d1, you must provide the Installation
127
- Information in the manner specified by section 6 of the GNU GPL
128
- for conveying Corresponding Source.)
129
-
130
- 5. Combined Libraries.
131
-
132
- You may place library facilities that are a work based on the
133
- Library side by side in a single library together with other library
134
- facilities that are not Applications and are not covered by this
135
- License, and convey such a combined library under terms of your
136
- choice, if you do both of the following:
137
-
138
- a) Accompany the combined library with a copy of the same work based
139
- on the Library, uncombined with any other library facilities,
140
- conveyed under the terms of this License.
141
-
142
- b) Give prominent notice with the combined library that part of it
143
- is a work based on the Library, and explaining where to find the
144
- accompanying uncombined form of the same work.
145
-
146
- 6. Revised Versions of the GNU Lesser General Public License.
147
-
148
- The Free Software Foundation may publish revised and/or new versions
149
- of the GNU Lesser General Public License from time to time. Such new
150
- versions will be similar in spirit to the present version, but may
151
- differ in detail to address new problems or concerns.
152
-
153
- Each version is given a distinguishing version number. If the
154
- Library as you received it specifies that a certain numbered version
155
- of the GNU Lesser General Public License "or any later version"
156
- applies to it, you have the option of following the terms and
157
- conditions either of that published version or of any later version
158
- published by the Free Software Foundation. If the Library as you
159
- received it does not specify a version number of the GNU Lesser
160
- General Public License, you may choose any version of the GNU Lesser
161
- General Public License ever published by the Free Software Foundation.
162
-
163
- If the Library as you received it specifies that a proxy can decide
164
- whether future versions of the GNU Lesser General Public License shall
165
- apply, that proxy's public statement of acceptance of any version is
166
- permanent authorization for you to choose that version for the
167
- Library.
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ == 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ == 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ == 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, inline functions and templates
70
+ (ten or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are
74
+ covered by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ == 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ d-0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ d-1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ == 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License, and convey such a combined library under terms of your
134
+ choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based
137
+ on the Library, uncombined with any other library facilities,
138
+ conveyed under the terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it
141
+ is a work based on the Library, and explaining where to find the
142
+ accompanying uncombined form of the same work.
143
+
144
+ == 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions
147
+ of the GNU Lesser General Public License from time to time. Such new
148
+ versions will be similar in spirit to the present version, but may
149
+ differ in detail to address new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the
152
+ Library as you received it specifies that a certain numbered version
153
+ of the GNU Lesser General Public License "or any later version"
154
+ applies to it, you have the option of following the terms and
155
+ conditions either of that published version or of any later version
156
+ published by the Free Software Foundation. If the Library as you
157
+ received it does not specify a version number of the GNU Lesser
158
+ General Public License, you may choose any version of the GNU Lesser
159
+ General Public License ever published by the Free Software Foundation.
160
+
161
+ If the Library as you received it specifies that a proxy can decide
162
+ whether future versions of the GNU Lesser General Public License shall
163
+ apply, that proxy's public statement of acceptance of any version is
164
+ permanent authorization for you to choose that version for the
165
+ Library.
168
166
 
data/HISTORY CHANGED
@@ -1,16 +1,18 @@
1
- == 0.0.0 // 2008-03-04
1
+ 2008-10-23 trans <transfire@gmail.com>
2
2
 
3
- * Started project.
3
+ * cleaned up work directory
4
+ * working on version 0.2.x
5
+ * added notes and ridoc reap services
6
+ * renamed some libs
4
7
 
5
8
 
6
- # Keep a running list of changes by version and date here.
7
- # This is uploaded as the ChangeLog in the release process.
8
- # It's better to keep a manual log, rather then use the log
9
- # generated by the SCM because the SCM log will have gritty
10
- # details with which end-users will not be concerned.
11
- #
12
- # If you want to use the SCM log anyway, you can of course
13
- # do so. Just "cp log/Changelog.txt CHANGES" prior to release.
14
- # (We might provide an automated option for this in the
15
- # future, but for now its a manual task.)
9
+ 2008-10-21 trans <transfire@gmail.com>
10
+
11
+ * Annotations is now module rather than a direct core extenstion to Module
12
+
13
+
14
+ 2008-10-17 trans <transfire@gmail.com>
15
+
16
+ * added .gitignore
17
+ * initial commit
16
18
 
data/MANIFEST CHANGED
@@ -1,9 +1,13 @@
1
1
  test
2
- test/test_toplevel_attribute.rb
3
2
  test/test_attribute.rb
4
- test/test_annotatable.rb
3
+ test/test_annotator.rb
5
4
  test/suite.rb
6
- test/test_toplevel_annotatable.rb
5
+ test/test_annotator_toplevel.rb
6
+ test/test_annotations.rb
7
+ test/test_attribute_toplevel.rb
8
+ test/test_anise.rb
9
+ test/test_anise_toplevel.rb
10
+ test/test_annotations_toplevel.rb
7
11
  RELEASE
8
12
  README
9
13
  HISTORY
@@ -18,9 +22,9 @@ meta/authors
18
22
  meta/contact
19
23
  lib
20
24
  lib/anise
21
- lib/anise/attributes.rb
22
- lib/anise/annotations.rb
23
- lib/anise/annotatable.rb
25
+ lib/anise/attribute.rb
26
+ lib/anise/annotation.rb
27
+ lib/anise/annotator.rb
24
28
  lib/anise.rb
25
29
  VERSION
26
30
  COPYING
data/README CHANGED
@@ -1,36 +1,32 @@
1
- = Annotable
1
+ = Anise
2
2
 
3
3
  http://anise.rubyforge.org
4
4
 
5
5
 
6
6
  == INTRODUCTION
7
7
 
8
- Annotable is an Annotations Systems for the Ruby programming
9
- lanaguage. Unlike other annotations system it is not a comment-based
10
- system. Rather, it is a dynamic annotations system operating at runtime.
8
+ Anise is an Annotations Systems for the Ruby programming lanaguage.
9
+ Unlike most other annotations systems it is not a comment-based
10
+ system, or a "macro" system that sits over-and-above the rest of the
11
+ code. Rather, Anise is a dynamic annotations system operating at runtime.
11
12
 
12
13
 
13
- == RELEASE NOTES
14
+ == RELEASE NOTES & RECENT CHANGES
14
15
 
15
16
  Please see the RELEASE file.
16
17
 
17
18
 
18
- == RECENT CHANGES
19
-
20
- Please see the HISTORY file.
21
-
22
-
23
19
  == INSTALLATION
24
20
 
25
21
  To install with RubyGems simply open a console and type:
26
22
 
27
- gem install annotable
23
+ gem install anise
28
24
 
29
25
  To manually install you will need Setup.rb (see http://setup.rubyforge.org).
30
26
  Then download the tarball package and do:
31
27
 
32
28
  $ tar -xvzf anise-0.4.0.tgz
33
- $ cd annotated-0.4.0.tgz
29
+ $ cd annotated-0.4.0
34
30
  $ sudo setup.rb all
35
31
 
36
32
 
@@ -41,7 +37,7 @@ unit tests.
41
37
 
42
38
  $ turn test/test_*
43
39
 
44
- But we have include a script test/suite.rb so you can easily run the
40
+ But we have include a script +test/suite.rb+ so you can easily run the
45
41
  unit tests with the testrb command:
46
42
 
47
43
  $ testrb test/suite.rb
data/RELEASE CHANGED
@@ -1,11 +1,20 @@
1
- = Anise 0.1 hits the streets.
1
+ = Anise 0.2.0 hits the streets.
2
2
 
3
- This is the initial release of Anise.
3
+ http://anise.rubyforge.org
4
+
5
+ This is the initial public release of Anise.
4
6
 
5
7
  Anise is a spin off the the Facets annotations.rb library.
6
8
  It includes the Annotations functionality, and adds
7
- a mixin, Annotatable, that makes it easy to add new
9
+ a mixin, Annotator, that makes it easy to add new
8
10
  annotations on the fly.
9
11
 
10
- http://anise.rubyforge.org
12
+ ---
13
+
14
+ ### 0.2.0 // 2008-09-23
15
+
16
+ 2 Major Enhancments
17
+
18
+ * All parts of lib are now modules and not core extensions.
19
+ * Names of modules are more consistant.
11
20
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- anise 0.1.1 beta (2008-09-27)
1
+ anise 0.2.0 beta (2008-09-27)
@@ -0,0 +1,160 @@
1
+ module Anise
2
+
3
+ # = Runtime Annotations
4
+ #
5
+ # The Annotation module is the heart of the Anise system.
6
+ # It provides the framework for annotating class or module related
7
+ # objects, typically symbols representing methods, with arbitrary
8
+ # metadata. These annotations do not do anything in themselves.
9
+ # They are simply data. But you can put them to use. For instance
10
+ # an attribute validator might check for an annotation called
11
+ # :valid and test against it.
12
+ #
13
+ # == Synopsis
14
+ #
15
+ # class X
16
+ # include Anise::Annotation
17
+ #
18
+ # attr :a
19
+ #
20
+ # ann :a, :desc => "A Number"
21
+ # end
22
+ #
23
+ # X.ann(:a, :desc) #=> "A Number"
24
+ #
25
+ # As stated, annotations need not only annotate methods, they are
26
+ # arbitrary, so they can be used for any purpose. For example, we
27
+ # may want to annotate instance variables.
28
+ #
29
+ # class X
30
+ # include Anise::Annotation
31
+ #
32
+ # ann :@a, :valid => lambda{ |x| x.is_a?(Integer) }
33
+ #
34
+ # def validate
35
+ # instance_variables.each do |iv|
36
+ # if validator = self.class.ann(iv)[:valid]
37
+ # value = instance_variable_get(iv)
38
+ # unless validator.call(vale)
39
+ # raise "Invalid value #{value} for #{iv}"
40
+ # end
41
+ # end
42
+ # end
43
+ # end
44
+ # end
45
+ #
46
+ # Or, we could even annotate the class itself.
47
+ #
48
+ # class X
49
+ # include Anise::Annotation
50
+ #
51
+ # ann self, :valid => lambda{ |x| x.is_a?(Integer) }
52
+ # end
53
+ #
54
+ # Altough annotations are arbitrary they are tied to the class or
55
+ # module they are defined within.
56
+ #
57
+ #--
58
+ # TODO: By using a global variable rather the definining a class
59
+ # instance variable for each class/module, it is possible to
60
+ # quicky scan all annotations for the entire system. To do
61
+ # the same without this would require scanning through
62
+ # the ObjectSpace. Should we do this?
63
+ # $annotations = Hash.new { |h,k| h[k] = {} }
64
+ #
65
+ # TODO: The ann(x).name notation is kind of nice. Would like to add that
66
+ # back-in if reasonable. This would require @annotations to be an
67
+ # OpenHash or OpenObject rather than just a Hash.
68
+ #++
69
+ module Annotation
70
+
71
+ def self.append_features(base)
72
+ base.extend self
73
+ end
74
+
75
+ # Stores this classes or modules annotations.
76
+ #
77
+ def annotations
78
+ #$annotations[self]
79
+ @annotations ||= {}
80
+ end
81
+
82
+ # Lookup an annotation. Unlike +annotations[ref]+
83
+ # this provides a complete annotation <i>heritage</i>,
84
+ # pulling annotations of the same reference name
85
+ # from ancestor classes and modules.
86
+ #
87
+ def annotation(ref)
88
+ ref = ref.to_sym
89
+ ann = {}
90
+ ancestors.reverse_each do |anc|
91
+ next unless anc.is_a?(Annotation)
92
+ #anc.annotations[ref] ||= {}
93
+ if anc.annotations[ref]
94
+ ann.update(anc.annotations[ref]) #.merge(ann)
95
+ end
96
+ end
97
+ return ann
98
+ #ancs = ancestors.select{ |a| a.is_a?(Annotations) }
99
+ #ancs.inject({}) do |memo, ancestor|
100
+ # ancestor.annotations[ref] ||= {}
101
+ # ancestor.annotations[ref].merge(memo)
102
+ #end
103
+ end
104
+
105
+ # Set or read annotations.
106
+ #
107
+ def ann( ref, keys_or_class=nil, keys=nil )
108
+ return annotation(ref) unless keys_or_class or keys
109
+
110
+ if Class === keys_or_class
111
+ keys ||= {}
112
+ keys[:class] = keys_or_class
113
+ else
114
+ keys = keys_or_class
115
+ end
116
+
117
+ if Hash === keys
118
+ ref = ref.to_sym
119
+ keys = keys.inject({}){ |h,(k,v)| h[k.to_sym] = v; h} #rekey
120
+ annotations[ref] ||= {}
121
+ annotations[ref].update(keys)
122
+ else
123
+ key = keys.to_sym
124
+ annotation(ref)[key]
125
+ end
126
+ end
127
+
128
+ # To change an annotation's value in place for a given class or module
129
+ # it first must be duplicated, otherwise the change may effect annotations
130
+ # in the class or module's ancestors.
131
+ #
132
+ def ann!( ref, keys_or_class=nil, keys=nil )
133
+ #return annotation(ref) unless keys_or_class or keys
134
+ return annotations[ref] unless keys_or_class or keys
135
+
136
+ if Class === keys_or_class
137
+ keys ||= {}
138
+ keys[:class] = keys_or_class
139
+ else
140
+ keys = keys_or_class
141
+ end
142
+
143
+ if Hash === keys
144
+ ref = ref.to_sym
145
+ keys = keys.inject({}){ |h,(k,v)| h[k.to_sym] = v; h} #rekey
146
+ annotations[ref] ||= {}
147
+ annotations[ref].update(keys)
148
+ else
149
+ key = keys.to_sym
150
+ annotations[ref][key] = annotation(ref)[key].dup
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+ end
157
+
158
+ # 2006-11-07 trans Created this ultra-concise version of annotations.
159
+ # Copyright (c) 2005, 2008 TigerOps
160
+