ick 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,7 @@ config/requirements.rb
8
8
  lib/ick.rb
9
9
  lib/ick/advisor.rb
10
10
  lib/ick/base.rb
11
+ lib/ick/bizarro.rb
11
12
  lib/ick/guard.rb
12
13
  lib/ick/sugar.rb
13
14
  lib/ick/tee.rb
@@ -21,11 +22,17 @@ setup.rb
21
22
  tasks/deployment.rake
22
23
  tasks/environment.rake
23
24
  tasks/website.rake
25
+ test/test_180_seconds.rb
26
+ test/test_advisor.rb
24
27
  test/test_helper.rb
25
28
  test/test_ick.rb
26
- test/test_advisor.rb
29
+ test/test_not.rb
30
+ website/180seconds.html
31
+ website/180seconds.txt
27
32
  website/index.html
28
33
  website/index.txt
34
+ website/inside.html
35
+ website/inside.txt
29
36
  website/javascripts/rounded_corners_lite.inc.js
30
37
  website/stylesheets/screen.css
31
38
  website/template.rhtml
data/lib/ick.rb CHANGED
@@ -5,4 +5,5 @@ require 'ick/wrap'
5
5
  require 'ick/advisor'
6
6
  require 'ick/guard'
7
7
  require 'ick/tee'
8
+ require 'ick/bizarro'
8
9
  require 'ick/sugar'
@@ -33,17 +33,17 @@ module Ick
33
33
  end
34
34
 
35
35
  def self.before *args, &proc # { |receiver, sym, *args| ... }
36
- self.around *args, &(lambda { |callback, receiver, sym, *args|
36
+ self.around(*args, &(lambda { |callback, receiver, sym, *args|
37
37
  proc.call(receiver, sym, *args)
38
38
  callback.call()
39
- })
39
+ }))
40
40
  end
41
41
 
42
42
  def self.after *args, &proc # { |receiver, sym, *args| ... }
43
- self.around *args, &(lambda { |callback, receiver, sym, *args|
43
+ self.around(*args, &(lambda { |callback, receiver, sym, *args|
44
44
  callback.call()
45
45
  proc.call(receiver, sym, *args)
46
- })
46
+ }))
47
47
  end
48
48
 
49
49
  def __invoke__(sym, *args, &block)
@@ -0,0 +1,41 @@
1
+ # Inspired by
2
+ # http://probablycorey.wordpress.com/2008/03/28/abusing-rubys-question-mark-methods/
3
+
4
+ module Ick
5
+
6
+ class Bizarro
7
+
8
+ def invoke(*values, &proc)
9
+ invoke_wrapped(values, ArrayWrapper, nil, &proc)
10
+ end
11
+
12
+ def unwrap(wrapped, wrapper_class)
13
+ wrapped.respond_to?(:__value__) ? wrapped.__value__.first : wrapped
14
+ end
15
+
16
+ def self.belongs_to clazz
17
+ method_name = self.underscore(self.name.split('::')[-1])
18
+ unless clazz.method_defined?(method_name)
19
+ clazz.class_eval "
20
+ def #{method_name}(*values,&proc)
21
+ values = [self] if values.empty?
22
+ if block_given?
23
+ #{self.name}.instance.invoke(*values, &proc)
24
+ else
25
+ Invoker.new(values, #{self.name})
26
+ end
27
+ end"
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ class Tee < Split
34
+ evaluates_in_calling_environment and returns_value
35
+ end
36
+
37
+ class Fork < Split
38
+ evaluates_in_calling_environment and returns_result
39
+ end
40
+
41
+ end
@@ -2,7 +2,7 @@ module Ick #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 2
5
- TINY = 3
5
+ TINY = 4
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -0,0 +1,100 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class Symbol
4
+ # Turns the symbol into a simple proc, which is especially useful for enumerations.
5
+ def to_proc
6
+ Proc.new { |*args| args.shift.__send__(self, *args) }
7
+ end
8
+ end
9
+
10
+ class Test180Seconds < Test::Unit::TestCase
11
+
12
+ def test_blocks
13
+ arr = []
14
+
15
+ # let returns the value of the block and executes in the current environment
16
+ assert_equal(
17
+ "3628800 ends with zero",
18
+ let((1..10).inject(&:*)) { |num|
19
+ arr << self.class
20
+ num % 10 == 0 ? "#{num} ends with zero" : "#{num} does not end with zero"
21
+ })
22
+ assert_equal([ self.class ], arr)
23
+
24
+ # returning returns the value of the expression and executes in the current environment
25
+ assert_equal(
26
+ 3628800,
27
+ returning((1..10).inject(&:*)) { |num|
28
+ arr << self.class
29
+ num % 10 == 0 ? "#{num} ends with zero" : "#{num} does not end with zero"
30
+ })
31
+ assert_equal([ self.class, self.class ], arr)
32
+
33
+ # my returns the value of the block and executes in the expression's environment
34
+ assert_equal(
35
+ "3628800 ends with zero",
36
+ my((1..10).inject(&:*)) { |num|
37
+ arr << self.class
38
+ num % 10 == 0 ? "#{num} ends with zero" : "#{num} does not end with zero"
39
+ })
40
+ assert_equal([ self.class, self.class, Fixnum ], arr)
41
+
42
+ # inside returns the value of the expression and executes in the expression's environment
43
+ assert_equal(
44
+ 3628800,
45
+ inside((1..10).inject(&:*)) { |num|
46
+ arr << self.class
47
+ num % 10 == 0 ? "#{num} ends with zero" : "#{num} does not end with zero"
48
+ })
49
+ assert_equal([ self.class, self.class, Fixnum, Fixnum ], arr)
50
+ end
51
+
52
+ def test_guards
53
+ arr = []
54
+
55
+ # an object with two methods. #do returns itself, #do_not returns nil
56
+ yoda = returning(Object.new) do |obj|
57
+ def obj.do
58
+ self
59
+ end
60
+ def obj.do_not
61
+ nil
62
+ end
63
+ end
64
+
65
+ # maybe handles nils, even for methods nil has, but not missing methods
66
+ assert_equal(
67
+ yoda,
68
+ maybe(yoda) { |obj| obj.do }
69
+ )
70
+ assert_nil(
71
+ maybe(nil) { |obj| obj.do }
72
+ )
73
+ assert_nil(
74
+ maybe(yoda) { |obj| obj.do_not.do }
75
+ )
76
+ assert_nil(
77
+ maybe(nil) { |obj| obj.nil? }
78
+ )
79
+ assert_raise(NoMethodError) do
80
+ maybe(yoda) { |obj| obj.fubar }
81
+ end
82
+
83
+ #try handles NoMethodErrors, without caring whether nil is involved
84
+ assert_equal(
85
+ yoda,
86
+ try(yoda) { |obj| obj.do }
87
+ )
88
+ assert_nil(
89
+ try(nil) { |obj| obj.do_not }
90
+ )
91
+ assert_not_nil(
92
+ try(nil) { |obj| obj.nil? }
93
+ )
94
+ assert_nil(
95
+ try(yoda) { |obj| obj.fubar }
96
+ )
97
+
98
+ end
99
+
100
+ end
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ def test_not
4
+
5
+ end
@@ -0,0 +1,239 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7
+ <title>
8
+ Ick in 180 seconds or less
9
+ </title>
10
+ <script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
11
+ <style>
12
+
13
+ </style>
14
+ <script type="text/javascript">
15
+ window.onload = function() {
16
+ settings = {
17
+ tl: { radius: 10 },
18
+ tr: { radius: 10 },
19
+ bl: { radius: 10 },
20
+ br: { radius: 10 },
21
+ antiAlias: true,
22
+ autoPad: true,
23
+ validTags: ["div"]
24
+ }
25
+ var versionBox = new curvyCorners(settings, document.getElementById("version"));
26
+ versionBox.applyCornersToAll();
27
+ }
28
+ </script>
29
+ </head>
30
+ <body>
31
+ <div id="main">
32
+
33
+ <h1>Ick in 180 seconds or less</h1>
34
+ <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/ick"; return false'>
35
+ <p>Get Version</p>
36
+ <a href="http://rubyforge.org/projects/ick" class="numbers">0.2.4</a>
37
+ </div>
38
+ <h2>Transforming your code</h2>
39
+
40
+
41
+ <p>Object#let turns:</p>
42
+
43
+
44
+ <p><pre class='syntax'>
45
+ </pre></p>
46
+
47
+
48
+ <p>Into:</p>
49
+
50
+
51
+ <p><pre class='syntax'>
52
+ </pre></p>
53
+
54
+
55
+ <p>Object#returning turns:</p>
56
+
57
+
58
+ <p><pre class='syntax'>
59
+ </pre></p>
60
+
61
+
62
+ <p>Into:</p>
63
+
64
+
65
+ <p><pre class='syntax'>
66
+ </pre></p>
67
+
68
+
69
+ <p>Object#my turns:</p>
70
+
71
+
72
+ <p><pre class='syntax'>
73
+ </pre></p>
74
+
75
+
76
+ <p>Into:</p>
77
+
78
+
79
+ <p><pre class='syntax'>
80
+ </pre></p>
81
+
82
+
83
+ <p>Object#inside turns:</p>
84
+
85
+
86
+ <p><pre class='syntax'>
87
+ </pre></p>
88
+
89
+
90
+ <p>Into:</p>
91
+
92
+
93
+ <p><pre class='syntax'>
94
+ </pre></p>
95
+
96
+
97
+ <h2>Test Cases</h2>
98
+
99
+
100
+ <p>The four canonical block structuring methods (#let, #returning, #my, and #inside):</p>
101
+
102
+
103
+ <p><pre class='syntax'>
104
+ <span class="constant">Ick</span><span class="punct">.</span><span class="ident">sugarize</span>
105
+ <span class="ident">arr</span> <span class="punct">=</span> <span class="punct">[]</span>
106
+
107
+ <span class="comment"># let returns the value of the block and executes in the current environment</span>
108
+ <span class="ident">assert_equal</span><span class="punct">(</span>
109
+ <span class="punct">&quot;</span><span class="string">3628800 ends with zero</span><span class="punct">&quot;,</span>
110
+ <span class="ident">let</span><span class="punct">((</span><span class="number">1</span><span class="punct">..</span><span class="number">10</span><span class="punct">).</span><span class="ident">inject</span><span class="punct">(&amp;:*))</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">num</span><span class="punct">|</span>
111
+ <span class="ident">arr</span> <span class="punct">&lt;&lt;</span> <span class="constant">self</span><span class="punct">.</span><span class="keyword">class
112
+ </span><span class="class">num</span> <span class="punct">%</span> <span class="number">10</span> <span class="punct">==</span> <span class="number">0</span> <span class="punct">?</span> <span class="punct">&quot;</span><span class="string"><span class="expr">#{num}</span> ends with zero</span><span class="punct">&quot;</span> <span class="punct">:</span> <span class="punct">&quot;</span><span class="string"><span class="expr">#{num}</span> does not end with zero</span><span class="punct">&quot;</span>
113
+ <span class="punct">})</span>
114
+ <span class="ident">assert_equal</span><span class="punct">([</span> <span class="constant">self</span><span class="punct">.</span><span class="keyword">class </span><span class="class">],</span> <span class="ident">arr</span><span class="punct">)</span>
115
+
116
+ <span class="comment"># returning returns the value of the expression and executes in the current environment</span>
117
+ <span class="ident">assert_equal</span><span class="punct">(</span>
118
+ <span class="number">3628800</span><span class="punct">,</span>
119
+ <span class="ident">returning</span><span class="punct">((</span><span class="number">1</span><span class="punct">..</span><span class="number">10</span><span class="punct">).</span><span class="ident">inject</span><span class="punct">(&amp;:*))</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">num</span><span class="punct">|</span>
120
+ <span class="ident">arr</span> <span class="punct">&lt;&lt;</span> <span class="constant">self</span><span class="punct">.</span><span class="keyword">class
121
+ </span><span class="class">num</span> <span class="punct">%</span> <span class="number">10</span> <span class="punct">==</span> <span class="number">0</span> <span class="punct">?</span> <span class="punct">&quot;</span><span class="string"><span class="expr">#{num}</span> ends with zero</span><span class="punct">&quot;</span> <span class="punct">:</span> <span class="punct">&quot;</span><span class="string"><span class="expr">#{num}</span> does not end with zero</span><span class="punct">&quot;</span>
122
+ <span class="punct">})</span>
123
+ <span class="ident">assert_equal</span><span class="punct">([</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">class</span><span class="punct">,</span> <span class="constant">self</span><span class="punct">.</span><span class="keyword">class </span><span class="class">],</span> <span class="ident">arr</span><span class="punct">)</span>
124
+
125
+ <span class="comment"># my returns the value of the block and executes in the expression's environment</span>
126
+ <span class="ident">assert_equal</span><span class="punct">(</span>
127
+ <span class="punct">&quot;</span><span class="string">3628800 ends with zero</span><span class="punct">&quot;,</span>
128
+ <span class="ident">my</span><span class="punct">((</span><span class="number">1</span><span class="punct">..</span><span class="number">10</span><span class="punct">).</span><span class="ident">inject</span><span class="punct">(&amp;:*))</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">num</span><span class="punct">|</span>
129
+ <span class="ident">arr</span> <span class="punct">&lt;&lt;</span> <span class="constant">self</span><span class="punct">.</span><span class="keyword">class
130
+ </span><span class="class">num</span> <span class="punct">%</span> <span class="number">10</span> <span class="punct">==</span> <span class="number">0</span> <span class="punct">?</span> <span class="punct">&quot;</span><span class="string"><span class="expr">#{num}</span> ends with zero</span><span class="punct">&quot;</span> <span class="punct">:</span> <span class="punct">&quot;</span><span class="string"><span class="expr">#{num}</span> does not end with zero</span><span class="punct">&quot;</span>
131
+ <span class="punct">})</span>
132
+ <span class="ident">assert_equal</span><span class="punct">([</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">class</span><span class="punct">,</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">class</span><span class="punct">,</span> <span class="constant">Fixnum</span> <span class="punct">],</span> <span class="ident">arr</span><span class="punct">)</span>
133
+
134
+ <span class="comment"># inside returns the value of the expression and executes in the expression's environment</span>
135
+ <span class="ident">assert_equal</span><span class="punct">(</span>
136
+ <span class="number">3628800</span><span class="punct">,</span>
137
+ <span class="ident">inside</span><span class="punct">((</span><span class="number">1</span><span class="punct">..</span><span class="number">10</span><span class="punct">).</span><span class="ident">inject</span><span class="punct">(&amp;:*))</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">num</span><span class="punct">|</span>
138
+ <span class="ident">arr</span> <span class="punct">&lt;&lt;</span> <span class="constant">self</span><span class="punct">.</span><span class="keyword">class
139
+ </span><span class="class">num</span> <span class="punct">%</span> <span class="number">10</span> <span class="punct">==</span> <span class="number">0</span> <span class="punct">?</span> <span class="punct">&quot;</span><span class="string"><span class="expr">#{num}</span> ends with zero</span><span class="punct">&quot;</span> <span class="punct">:</span> <span class="punct">&quot;</span><span class="string"><span class="expr">#{num}</span> does not end with zero</span><span class="punct">&quot;</span>
140
+ <span class="punct">})</span>
141
+ <span class="ident">assert_equal</span><span class="punct">([</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">class</span><span class="punct">,</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">class</span><span class="punct">,</span> <span class="constant">Fixnum</span><span class="punct">,</span> <span class="constant">Fixnum</span> <span class="punct">],</span> <span class="ident">arr</span><span class="punct">)</span>
142
+ </pre></p>
143
+
144
+
145
+ <p>The two most common guarded evauators (#maybe and #try):</p>
146
+
147
+
148
+ <p><pre class='syntax'>
149
+ <span class="comment"># an object with two methods. #do returns itself, #do_not returns nil</span>
150
+ <span class="ident">yoda</span> <span class="punct">=</span> <span class="ident">returning</span><span class="punct">(</span><span class="constant">Object</span><span class="punct">.</span><span class="ident">new</span><span class="punct">)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span>
151
+ <span class="keyword">def </span><span class="method">obj.do</span>
152
+ <span class="constant">self</span>
153
+ <span class="keyword">end</span>
154
+ <span class="keyword">def </span><span class="method">obj.do_not</span>
155
+ <span class="constant">nil</span>
156
+ <span class="keyword">end</span>
157
+ <span class="keyword">end</span>
158
+
159
+ <span class="comment"># maybe handles nils, even for methods nil has, but not missing methods</span>
160
+ <span class="ident">assert_equal</span><span class="punct">(</span>
161
+ <span class="ident">yoda</span><span class="punct">,</span>
162
+ <span class="ident">maybe</span><span class="punct">(</span><span class="ident">yoda</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">do</span> <span class="punct">}</span>
163
+ <span class="punct">)</span>
164
+ <span class="ident">assert_nil</span><span class="punct">(</span>
165
+ <span class="ident">maybe</span><span class="punct">(</span><span class="constant">nil</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">do</span> <span class="punct">}</span>
166
+ <span class="punct">)</span>
167
+ <span class="ident">assert_nil</span><span class="punct">(</span>
168
+ <span class="ident">maybe</span><span class="punct">(</span><span class="ident">yoda</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">do_not</span><span class="punct">.</span><span class="ident">do</span> <span class="punct">}</span>
169
+ <span class="punct">)</span>
170
+ <span class="ident">assert_nil</span><span class="punct">(</span>
171
+ <span class="ident">maybe</span><span class="punct">(</span><span class="constant">nil</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">nil?</span> <span class="punct">}</span>
172
+ <span class="punct">)</span>
173
+ <span class="ident">assert_raise</span><span class="punct">(</span><span class="constant">NoMethodError</span><span class="punct">)</span> <span class="keyword">do</span>
174
+ <span class="ident">maybe</span><span class="punct">(</span><span class="ident">yoda</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">fubar</span> <span class="punct">}</span>
175
+ <span class="keyword">end</span>
176
+
177
+ <span class="comment">#try handles NoMethodErrors, without caring whether nil is involved</span>
178
+ <span class="ident">assert_equal</span><span class="punct">(</span>
179
+ <span class="ident">yoda</span><span class="punct">,</span>
180
+ <span class="ident">try</span><span class="punct">(</span><span class="ident">yoda</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">do</span> <span class="punct">}</span>
181
+ <span class="punct">)</span>
182
+ <span class="ident">assert_nil</span><span class="punct">(</span>
183
+ <span class="ident">try</span><span class="punct">(</span><span class="constant">nil</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">do_not</span> <span class="punct">}</span>
184
+ <span class="punct">)</span>
185
+ <span class="ident">assert_not_nil</span><span class="punct">(</span>
186
+ <span class="ident">try</span><span class="punct">(</span><span class="constant">nil</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">nil?</span> <span class="punct">}</span>
187
+ <span class="punct">)</span>
188
+ <span class="ident">assert_nil</span><span class="punct">(</span>
189
+ <span class="ident">try</span><span class="punct">(</span><span class="ident">yoda</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">obj</span><span class="punct">|</span> <span class="ident">obj</span><span class="punct">.</span><span class="ident">fubar</span> <span class="punct">}</span>
190
+ <span class="punct">)</span>
191
+ </pre></p>
192
+
193
+
194
+ <h2>Administrivia</h2>
195
+
196
+
197
+ <h3>Home Sweet Home</h3>
198
+
199
+
200
+ <p><a href="http://ick.rubyforge.org">ick.rubyforge.org</a></p>
201
+
202
+
203
+ <h3>How to submit patches</h3>
204
+
205
+
206
+ <p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people&#8217;s code</a>.</p>
207
+
208
+
209
+ <p>The trunk repository is <code>svn://rubyforge.org/var/svn/ick/trunk</code> for anonymous access.</p>
210
+
211
+
212
+ <h3>License</h3>
213
+
214
+
215
+ <p>This code is free to use under the terms of the <a href="http://en.wikipedia.org/wiki/MIT_License"><span class="caps">MIT</span> license</a>.</p>
216
+
217
+
218
+ <h3>Shout Out</h3>
219
+
220
+
221
+ <p><a href="http://mcommons.com/">Mobile Commons</a>. Still Huge After All These Years.</p>
222
+
223
+
224
+ <h3>Contact</h3>
225
+
226
+
227
+ <p>Comments are welcome. Send an email to <a href="mailto:raganwald+rubyforge@gmail.com">Reginald Braithwaite</a>. And you can always visit <a href="http://weblog.raganwald.com/">weblog.raganwald.com</a> to see what&#8217;s cooking.</p>
228
+ <p class="coda">
229
+ <a href="http://weblog.raganwald.com/">Reginald Braithwaite</a>, 10th March 2008<br>
230
+ Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
231
+ </p>
232
+ </div>
233
+
234
+ <!-- insert site tracking codes here, like Google Urchin -->
235
+
236
+ <script type="text/javascript" src="http://pub44.bravenet.com/counter/code.php?id=404724&usernum=3754613835&cpv=2"></script>
237
+
238
+ </body>
239
+ </html>