flatulent 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -5,7 +5,7 @@ NAME
5
5
  SYNOPSIS
6
6
 
7
7
  the flatulent gem provides brain dead simple to use, but internally cunning,
8
- ascii art captcha for ruby.
8
+ ascii art (figlet) captcha for ruby.
9
9
 
10
10
  URI
11
11
 
@@ -17,6 +17,21 @@ HOW DO I GET FLATULENT?
17
17
  gem install flatulent
18
18
 
19
19
  HISTORY
20
+ 0.0.3:
21
+ - following are now all equivalent when posting (thanks botp)
22
+
23
+ 0==o==O==Q (zero, oh's, and queue)
24
+ l==l (one and el)
25
+ 2==z==Z (two and z's)
26
+ 5==s==S (5 and s's)
27
+
28
+ - random horizontal and vertical displacement of each char
29
+
30
+ - vastly improved background noise based on figlet char shapes
31
+
32
+ - inputs are case sensitive (thanks john joyce, chris carter)
33
+
34
+ - expanded rails examples
20
35
 
21
36
  0.0.2
22
37
 
@@ -78,7 +93,9 @@ DOCS
78
93
 
79
94
  ONLINE SAMPLES
80
95
 
96
+ http://drawohara.tumblr.com/post/4791838
81
97
  http://drawohara.tumblr.com/post/4944987
98
+ http://drawohara.tumblr.com/post/4968766
82
99
 
83
100
  ONLINE DEMO OF AJAX METHOD
84
101
 
data/flatulent-0.0.2.gem CHANGED
Binary file
data/lib/flatulent.rb CHANGED
@@ -1,10 +1,5 @@
1
- # TODO - encrypt time
2
- # TODO - noise is image chars
3
- # TODO - newline in value??
4
- # TODO - vertical offset in chars
5
-
6
1
  class Flatulent
7
- Flatulent::VERSION = '0.0.2' unless defined? Flatulent::VERSION
2
+ Flatulent::VERSION = '0.0.3' unless defined? Flatulent::VERSION
8
3
  def self.flatulent() Flatulent::VERSION end
9
4
  def self.libdir() File.expand_path(__FILE__).gsub(%r/\.rb$/, '') end
10
5
 
@@ -15,6 +10,7 @@ class Flatulent
15
10
  begin
16
11
  require 'rubygems'
17
12
  rescue LoadError
13
+ 42
18
14
  end
19
15
 
20
16
  begin
@@ -31,7 +27,6 @@ class Flatulent
31
27
  class EncryptionError < Error; end
32
28
  class TimeBombError < Error; end
33
29
 
34
-
35
30
  singleton_class =
36
31
  class << self
37
32
  self
@@ -46,29 +41,27 @@ class Flatulent
46
41
  'font-family' => 'monospace',
47
42
  'font-weight' => 'bold',
48
43
  'font-size' => 'medium',
49
- 'background' => '#ffc',
50
- 'color' => '#00f',
44
+ #'background' => '#ffc',
45
+ 'background' => '#ccffcc',
46
+ #'color' => '#000',
47
+ 'color' => '#330066',
51
48
  'margin' => '2px',
52
49
  'padding' => '2px',
53
50
  'display' => 'table',
54
51
  ] }
55
52
 
56
- attribute('noise_style'){ Hash[
57
- 'color' => '#ccc',
58
- ] }
59
-
60
53
  attribute('key'){ default_key }
61
54
 
62
- def valid? keywords = {}
55
+ def valid? keywords = {} #--{{{
63
56
  begin
64
57
  validate! keywords
65
58
  true
66
59
  rescue EncryptionError, TimeBombError
67
60
  false
68
61
  end
69
- end
62
+ end #--}}}
70
63
 
71
- def validate! keywords = {}
64
+ def validate! keywords = {} #--{{{
72
65
  keywords = keywords['flatulent'] if keywords.has_key?('flatulent')
73
66
  keywords = keywords[:flatulent] if keywords.has_key?(:flatulent)
74
67
 
@@ -78,8 +71,8 @@ class Flatulent
78
71
  string = opts['s'] or raise 'no string'
79
72
  time = opts['t'] or raise 'no time'
80
73
 
81
- expected = zeroh(decrypt(string))
82
- actual = zeroh(captcha)
74
+ expected = fuzzy(decrypt(string))
75
+ actual = fuzzy(captcha)
83
76
  raise EncryptionError, "expected #{ expected } got #{ actual }" unless
84
77
  expected == actual
85
78
 
@@ -87,29 +80,44 @@ class Flatulent
87
80
  raise TimeBombError unless Time.now.utc <= timebomb
88
81
 
89
82
  return actual
90
- end
91
-
92
- def zeroh string
93
- string.gsub(%r/[0Oo]/, '0') # ignore diffs between 0/o/O
94
- end
83
+ end #--}}}
84
+
85
+ # 0==o==O (zero and oh's)
86
+ # l==l (one and el)
87
+ # 2==z==Z (two and z's)
88
+ # 5==s==S (5 and s's)
89
+ def fuzzy string #--{{{
90
+ result = string.dup
91
+ close_enough = {
92
+ '0OoQ' => '0',
93
+ '1l' => '1',
94
+ '2zZ' => '2',
95
+ '5sS' => '5',
96
+ }
97
+ #string.gsub(%r/[0Oo]/, '0') # ignore diffs between 0/o/O
98
+ close_enough.each do |chars,char|
99
+ result.gsub! %r"[#{ chars }]", char
100
+ end
101
+ result
102
+ end #--}}}
95
103
 
96
- def blowfish
104
+ def blowfish #--{{{
97
105
  @blowfish ||= Hash.new{|h,k| h[k] = Crypt::Blowfish.new(key)}
98
- end
106
+ end #--}}}
99
107
 
100
- def munge string
101
- string.strip.downcase
102
- end
108
+ def munge string #--{{{
109
+ string.strip #.downcase
110
+ end #--}}}
103
111
 
104
- def encrypt string
112
+ def encrypt string #--{{{
105
113
  Base64.encode64(blowfish[key].encrypt_string(string.to_s)).chop # kill "\n"
106
- end
114
+ end #--}}}
107
115
 
108
- def decrypt string
116
+ def decrypt string #--{{{
109
117
  munge(blowfish[key].decrypt_string(Base64.decode64("#{ string }\n")))
110
- end
118
+ end #--}}}
111
119
 
112
- def getopts options
120
+ def getopts options #--{{{
113
121
  lambda do |key, *default|
114
122
  default = default.first
115
123
  break options[key] if options.has_key?(key)
@@ -119,22 +127,18 @@ class Flatulent
119
127
  break options[key] if options.has_key?(key)
120
128
  break default
121
129
  end
122
- end
130
+ end #--}}}
123
131
 
124
- def default_key
125
- #attribute('default_key') do
132
+ def default_key #--{{{
126
133
  return @default_key if defined? @default_key
127
134
  require 'socket'
128
135
  hostname = Socket.gethostname
129
136
  maddr = mac_address rescue nil
130
137
  warn "could not determine mac addresss!" unless maddr
131
- #puts(( Digest::MD5.hexdigest "--#{ hostname }--#{ maddr }--" ))
132
- #Digest::MD5.hexdigest "--#{ hostname }--#{ maddr }--"
133
- #@default_key = "--#{ hostname }--#{ maddr }--"
134
138
  @default_key = "--#{ hostname }--#{ maddr }--"
135
- end
139
+ end #--}}}
136
140
 
137
- def mac_address
141
+ def mac_address #--{{{
138
142
  return @mac_address if defined? @mac_address
139
143
  re = %r/[^:\-](?:[0-9A-F][0-9A-F][:\-]){5}[0-9A-F][0-9A-F][^:\-]/io
140
144
  cmds = '/sbin/ifconfig', '/bin/ifconfig', 'ifconfig', 'ipconfig /all'
@@ -160,28 +164,33 @@ class Flatulent
160
164
  maddr.instance_eval{ @list = candidates; def list() @list end }
161
165
 
162
166
  @mac_address = maddr
163
- end
167
+ end #--}}}
164
168
 
165
- def figlet options = {}
169
+ def figlet options = {} #--{{{
166
170
  new(options).figlet
167
- end
168
- def figlets options = {}
171
+ end #--}}}
172
+
173
+ def figlets options = {} #--{{{
169
174
  new(options).figlets
170
- end
171
- def element options = {}
175
+ end #--}}}
176
+
177
+ def element options = {} #--{{{
172
178
  new(options).element
173
- end
174
- def form_tags options = {}
179
+ end #--}}}
180
+
181
+ def form_tags options = {} #--{{{
175
182
  new(options).form_tags
176
- end
177
- def form options = {}
183
+ end #--}}}
184
+
185
+ def form options = {} #--{{{
178
186
  new(options).form
179
- end
187
+ end #--}}}
180
188
 
181
- def latest_prototype_lib
189
+ def latest_prototype_lib #--{{{
182
190
  'http://www.prototypejs.org/assets/2007/6/20/prototype.js'
183
- end
184
- def require_prototype
191
+ end #--}}}
192
+
193
+ def require_prototype #--{{{
185
194
  %Q`
186
195
  <script type="text/javascript">
187
196
  var prototype = true;
@@ -204,8 +213,9 @@ class Flatulent
204
213
  }
205
214
  </script>
206
215
  `
207
- end
208
- def javascript options = {}
216
+ end #--}}}
217
+
218
+ def javascript options = {} #--{{{
209
219
  id = options[:id] || options['id'] || 'flatulent'
210
220
  url = options[:url] || options['url'] || '/flatulent/captcha'
211
221
  %Q`
@@ -214,14 +224,15 @@ class Flatulent
214
224
  new Ajax.Updater('#{ id }', '#{ url }', { method: 'get' });
215
225
  </script>
216
226
  `
217
- end
218
- def ajax options = {}
227
+ end #--}}}
228
+
229
+ def ajax options = {} #--{{{
219
230
  id = options[:id] || options['id'] || 'flatulent'
220
231
  %Q`
221
232
  <div id="#{ id }"></div>
222
233
  #{ Flatulent.javascript }
223
234
  `
224
- end
235
+ end #--}}}
225
236
  end
226
237
 
227
238
  singleton_class.attributes.each{|a| attribute(a){ self.class.send a}}
@@ -235,12 +246,14 @@ class Flatulent
235
246
  attribute 'ttl'
236
247
 
237
248
  attribute 'figlet'
249
+ attribute 'vapour'
250
+ attribute 'captcha'
238
251
  attribute 'figlets'
239
252
  attribute 'element'
240
253
  attribute 'form_tags'
241
254
  attribute 'form'
242
255
 
243
- def initialize arg = {}
256
+ def initialize arg = {} #--{{{
244
257
  if Hash === arg
245
258
  opt = getopts arg
246
259
  @size = Integer opt[ 'size', 4 ]
@@ -252,37 +265,209 @@ class Flatulent
252
265
  end
253
266
 
254
267
  @font = String opt[ 'font', 'big' ]
255
- @noise = Float opt[ 'noise', 0.04 ]
268
+ @noise = Float opt[ 'noise', 0.22 ]
256
269
  @id = String opt[ 'id', 'flatulent' ]
257
270
  @action = String opt[ 'action' ]
258
- @ttl = Integer opt[ 'ttl', 256 ]
271
+ @ttl = Integer opt[ 'ttl', 300 ]
272
+ @horizontal_fudge_factor = Integer opt[ 'horizontal_fudge_factor', 4 ]
273
+ @vertical_fudge_factor = Integer opt[ 'vertical_fudge_factor', 4 ]
274
+
275
+ @vapour_chars = Integer opt[ 'vapour_chars', 5 * @size ]
276
+ @vapour_level = Float opt[ 'vapour_level', 0.77 ]
259
277
 
260
278
  figlet!
279
+ vapour!
280
+ captcha!
261
281
  element!
262
282
  form_tags!
263
283
  form!
264
- end
284
+ end #--}}}
285
+
286
+ def random_charset #--{{{
287
+ return @random_charset if defined? @random_charset
288
+ @random_charset = ('A' .. 'Z').to_a + ('1' .. '9').to_a
289
+ end #--}}}
290
+
291
+ def generate_random_string #--{{{
292
+ chars = []
293
+ n = random_charset.size - 1
294
+ loop {
295
+ ( chars << random_charset[rand(n)] ).uniq!
296
+ break if chars.size >= @size or random_charset.size == chars.size
297
+ }
298
+ chars
299
+ end #--}}}
300
+
301
+ def random_char #--{{{
302
+ n = random_charset.size - 1
303
+ random_charset[rand(n)]
304
+ end #--}}}
305
+
306
+ def figlet! #--{{{
307
+ #spaced = @string.split(%r//).join #' ' #.join(' ')
308
+ fontfile = File.join fontdir, "#{ @font }.flf"
309
+ font = Text::Figlet::Font.new fontfile
310
+ typesetter = Text::Figlet::Typesetter.new font
265
311
 
266
- def generate_random_string
267
- chars = ('A' .. 'Z').to_a + ('1' .. '9').to_a ### zero is too much like o/O
268
- Array.new(@size).map{ chars[rand(chars.size - 1)]}.join
269
- end
312
+ @figlets = []
313
+ chars = @string.split %r//
314
+ #chars.each{|char| @figlets << typesetter[char]}
315
+
316
+ # horz fudge
317
+ chars.each do |char|
318
+ figlet = typesetter[char]
319
+ rows = figlet.split %r/\n/
320
+ height = rows.size
321
+ offset_l = " " * rand(@horizontal_fudge_factor)
322
+ offset_r = " " * rand(@horizontal_fudge_factor)
323
+ rows.size.times do |i|
324
+ rows[i] = "#{ offset_l }#{ rows[i] }#{ offset_r }"
325
+ end
326
+ @figlets.push rows
327
+ end
328
+
329
+ # vert fudge
330
+ @figlets.map! do |rows|
331
+ width = rows.first.size
332
+ offset_t = Array.new(rand(@vertical_fudge_factor)).map{ " " * width }
333
+ offset_b = Array.new(rand(@vertical_fudge_factor)).map{ " " * width }
334
+ offset_t + rows + offset_b
335
+ end
270
336
 
271
- def figlet!
272
- spaced = @string.split(%r//).join #.join(' ')
337
+ # vert normalize vert
338
+ tallest = @figlets.map{|rows| rows.size}.max
339
+ @figlets.size.times do |i|
340
+ rows = @figlets[i]
341
+ unless rows.size == tallest
342
+ width = rows.first.size
343
+ until rows.size == tallest
344
+ blank = " " * width
345
+ rows << blank
346
+ end
347
+ end
348
+ end
349
+
350
+ # generate final grid
351
+ grid = []
352
+ grid << (gridrow = '')
353
+ catch :done do
354
+ loop do
355
+ @figlets.each do |rows|
356
+ row = rows.shift || throw(:done)
357
+ gridrow << row
358
+ end
359
+ #gridrow << "\n"
360
+ grid << (gridrow = '')
361
+ end
362
+ end
363
+
364
+ # trim top and bottom iff emtpy
365
+ =begin
366
+ empty = lambda{|row| not rnow.detect{|cell| cell !~ %r"br|nbsp"}}
367
+ grid.delete_if{|row| row.strip.empty?}
368
+ =end
369
+
370
+ @figlet_width = grid.first.size
371
+ @figlet_height = grid.size
372
+ @figlet = grid.join("\n")
373
+ end #--}}}
374
+
375
+ def vapour! #--{{{
376
+ #spaced = @string.split(%r//).join #' ' #.join(' ')
273
377
  fontfile = File.join fontdir, "#{ @font }.flf"
274
378
  font = Text::Figlet::Font.new fontfile
275
379
  typesetter = Text::Figlet::Typesetter.new font
276
- @figlets = []
277
- chars = spaced.split %r//
278
- chars.each{|char| @figlets << typesetter[char]}
279
- @figlet = typesetter[spaced]
280
- end
281
380
 
282
- def element!
381
+ grid = Array.new(@figlet_height).map{ Array.new(@figlet_width){ " " } }
382
+ width = grid.first.size
383
+ height = grid.size
384
+
385
+ @vapour_chars.times do
386
+ figlet = typesetter[random_char]
387
+
388
+ idxs = []
389
+ space = " "[0]
390
+ newline = "\n"[0]
391
+ i = 0
392
+ figlet.each_byte do |byte|
393
+ idxs << i unless byte == space or byte == newline
394
+ i += 1
395
+ end
396
+ #p idxs
397
+ to_vapourize = idxs.sort_by{ rand }.first((idxs.size * @vapour_level).ceil)
398
+ #p to_vapourize
399
+ to_vapourize.each{|idx| figlet[idx] = " "}
400
+ #puts figlet
401
+
402
+ figlet_grid = [] and figlet.each_line do |line|
403
+ figlet_grid << line.chomp.split(%r"")
404
+ end
405
+
406
+ xoff = rand(width - 1)
407
+ yoff = rand(height - 1)
408
+
409
+ figlet_grid.each_with_index do |row, y|
410
+ row.each_with_index do |char, x|
411
+ j = y + yoff
412
+ i = x + xoff
413
+ next if j >= height or i >= width
414
+ next if char == " "
415
+ grid[ y + yoff ][ x + xoff ] = char
416
+ end
417
+ end
418
+ end
419
+
420
+ @vapour = grid.map{|row| row.join}.join("\n")
421
+ end #--}}}
422
+
423
+ def captcha! #--{{{
424
+ @captcha = " " * @figlet.size
425
+ space = " "[0]
426
+ newline = "\n"[0]
427
+ noisy = %w`| / - _ ( ) \\ ! [ ]`
428
+
429
+ @figlet.size.times do |i|
430
+ fbyte = @figlet[i]
431
+ vbyte = @vapour[i]
432
+
433
+ if fbyte == newline
434
+ @captcha[i] = newline
435
+ elsif fbyte == space
436
+ #if vbyte == space
437
+ #@captcha[i] = noisy[ rand(noisy.size) ]
438
+ #else
439
+ @captcha[i] = vbyte
440
+ #end
441
+ else
442
+ @captcha[i] = fbyte
443
+ end
444
+ end
445
+
446
+
447
+ =begin
448
+ alpha = ('A'..'Z').to_a + ('a'..'z').to_a
449
+ transform = {
450
+ '|' => rchar(%w'. * \` + , ; : '),
451
+ '/' => rchar(%w'\\ ] [ { } ( ) @' + alpha),
452
+ '\\' => rchar(%w'/ ] [ { } ( ) @' + alpha),
453
+ '-' => rchar(%w'_ * ^ # @ ~'),
454
+ '_' => rchar(%w'- * ^ # @ ~'),
455
+ '(' => rchar(%w'\\ / ] [ { } ) @' + alpha),
456
+ ')' => rchar(%w'\\ / ] [ { } ( @' + alpha),
457
+ }
458
+
459
+ (@noise * @captcha.size).ceil.times do |i|
460
+ cbyte = @captcha[i]
461
+ if cell =~ %r"nbsp;"
462
+ end
463
+ =end
464
+ @captcha
465
+ end #--}}}
466
+
467
+ def element! #--{{{
283
468
  rows = []
284
469
  rows << (row = [])
285
- chars = @figlet.split %r//
470
+ chars = @captcha.split %r//
286
471
  size = chars.size
287
472
  last = size - 1
288
473
 
@@ -292,100 +477,64 @@ class Flatulent
292
477
  when %r/\n/o
293
478
  "<br>"
294
479
  when %r/\s/o
295
- #rand > 0.42 ? "&nbsp;" : " "
296
480
  "&nbsp;"
297
481
  when %r/([^\s])/o
298
482
  CGI.escapeHTML $1
299
483
  end
300
- Array.new(rand(42)){ content = "<span>#{ content }</span>"}
484
+ Array.new(rand(10)){ content = "<span>#{ content }</span>"}
301
485
  row << content
302
486
  rows << (row = []) unless idx == last
303
487
  end
304
488
 
305
- noisy = %W` | / - _ ( ) \ `
489
+
490
+ =begin
491
+ noisy = %w`| / - _ ( ) \\`
492
+ alpha = ('A'..'Z').to_a + ('a'..'z').to_a
493
+ transform = {
494
+ '|' => rchar(%w'. * \` + , ; : '),
495
+ '/' => rchar(%w'\\ ] [ { } ( ) @' + alpha),
496
+ '\\' => rchar(%w'/ ] [ { } ( ) @' + alpha),
497
+ '-' => rchar(%w'_ * ^ # @ ~'),
498
+ '_' => rchar(%w'- * ^ # @ ~'),
499
+ '(' => rchar(%w'\\ / ] [ { } ) @' + alpha),
500
+ ')' => rchar(%w'\\ / ] [ { } ( @' + alpha),
501
+ }
502
+
306
503
  (@noise * chars.size).ceil.times do
307
504
  y = rand(rows.size - 1)
308
505
  x = rand(rows.first.size - 1)
309
- next if rows[y][x] =~ %r"br"
310
- char = noisy[ rand(noisy.size) ]
311
- rows[y][x] = char
506
+ cell = rows[y][x]
507
+ next if cell =~ %r"br"
508
+ char =
509
+ if cell =~ %r"nbsp;"
510
+ noisy[ rand(noisy.size) ]
511
+ else
512
+ #(transform[cell] || lambda{'.'}).call
513
+ nil
514
+ end
515
+ rows[y][x] = char if char
312
516
  end
517
+ =end
313
518
 
314
519
  content = rows.join
315
520
  @element = "<pre id='#{ @id }_element' style='#{ css }'>#{ content }</pre>"
316
- end
521
+ end #--}}}
317
522
 
318
- =begin
523
+ def rchar *list #--{{{
524
+ list = list.flatten
525
+ n = list.size - 1
526
+ lambda{list[ rand(n) ]}
527
+ end #--}}}
319
528
 
320
- def element!
321
- cells = []
322
-
323
- @figlets.each do |figlet|
324
- rows = []
325
- rows << (row = [])
326
-
327
- offset_t = Array.new(rand(4)).map{ "\n"}
328
- offset_b = Array.new(rand(4)).map{ "\n"}
329
-
330
- offset_l = Array.new(rand(4)).map{ " "}
331
- offset_r = Array.new(rand(4)).map{ " "}
332
-
333
- chars = offset_t + figlet.split(%r//) + offset_b
334
- size = chars.size
335
- last = size - 1
336
- #drawn = chars.select{|char| char !~ %r/\s/}
337
- drawn = %w` | / \ &lt; &gt; v ^ - _ ( ) `
338
-
339
- chars.each_with_index do |char, idx|
340
- content =
341
- case char
342
- when %r/\n/o
343
- "<br>"
344
- when %r/\s/o
345
- #rand > 0.42 ? "&nbsp;" : " "
346
- "&nbsp;"
347
- when %r/([^\s])/o
348
- CGI.escapeHTML $1
349
- end
350
- #rand(10).times{ content = "<span>#{ content }</span>" }
351
- row << content
352
- rows << (row = []) unless idx == last
353
- end
354
-
355
- noisy = %w` | / \ - _ ( ) `
356
- (@noise * chars.size).ceil.times do
357
- y = rand(rows.size - 1)
358
- x = rand(rows.first.size - 1)
359
- next if rows[y][x] == "<br>"
360
- char = noisy[ rand(noisy.size) ]
361
- rows[y][x] = char
362
- end
363
-
364
- content = rows.join
365
- cells << content
366
- end
367
-
368
- formatted = lambda{|x| "<pre class='#{ @id }_figlet' style='#{ css }'>#{ x }</pre>"}
369
-
370
- @element =
371
- "<table id='#{ @id }_element' border='0' cellpadding='0' cellspacing='0' bgcolor='#{ style["background"] }'><tr>" <<
372
- cells.map{|cell| "<td>#{ formatted[cell] }</td>"}.join <<
373
- "</tr></table>"
374
- end
375
- =end
376
-
377
- def css
529
+ def css #--{{{
378
530
  css_for style
379
- end
380
- def noise_css
381
- css_for noise_style
382
- end
531
+ end #--}}}
383
532
 
384
- def css_for hash
533
+ def css_for hash #--{{{
385
534
  hash.map{|kv| kv.join ':' }.join ';'
386
- end
535
+ end #--}}}
387
536
 
388
- def form_tags!
537
+ def form_tags! #--{{{
389
538
  n = @string.scan(%r/\w/).size
390
539
  string = @string
391
540
  timebomb = Time.now.utc.to_i + @ttl
@@ -398,22 +547,22 @@ class Flatulent
398
547
  <input type='hidden' name='#{ @id }[s]' id='#{ @id }_e' value='#{ encrypt string }' />
399
548
  <input type='hidden' name='#{ @id }[t]' id='#{ @id }_v' value='#{ encrypt timebomb }' />
400
549
  html
401
- end
550
+ end #--}}}
402
551
  alias_method 'to_html', 'form_tags'
403
552
 
404
- def encrypt string
553
+ def encrypt string #--{{{
405
554
  self.class.encrypt string.to_s
406
- end
555
+ end #--}}}
407
556
 
408
- def encrypted
557
+ def encrypted #--{{{
409
558
  self.class.encrypt @string
410
- end
559
+ end #--}}}
411
560
 
412
- def munge string
561
+ def munge string #--{{{
413
562
  self.class.munge string
414
- end
563
+ end #--}}}
415
564
 
416
- def form!
565
+ def form! #--{{{
417
566
  action = "action='#{ @action }'"
418
567
  @form = <<-html
419
568
  <form method='post' #{ action }>
@@ -421,19 +570,19 @@ class Flatulent
421
570
  <input type='submit' name='#{ @id }[submit]' id='#{ @id }_submit' value='Submit' />
422
571
  </form>
423
572
  html
424
- end
573
+ end #--}}}
425
574
 
426
- def to_html
575
+ def to_html #--{{{
427
576
  element
428
- end
577
+ end #--}}}
429
578
 
430
- def to_s
579
+ def to_s #--{{{
431
580
  form
432
- end
581
+ end #--}}}
433
582
 
434
- def getopts options
583
+ def getopts options #--{{{
435
584
  self.class.getopts options
436
- end
585
+ end #--}}}
437
586
  end
438
587
 
439
588
  def Flatulent(*a, &b) Flatulent.new(*a, &b) end
@@ -446,5 +595,10 @@ if $0 == __FILE__
446
595
  #p e
447
596
  #p Flatulent.decrypt(e)
448
597
 
449
- puts Flatulent.figlet('foobar')
598
+ f = Flatulent.new #('foobar')
599
+ puts f.figlet
600
+ puts('-' * 79)
601
+ puts f.vapour
602
+ puts('-' * 79)
603
+ puts f.captcha
450
604
  end