tarantula 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.autotest +14 -0
  2. data/.gitignore +9 -0
  3. data/.rvmrc +1 -0
  4. data/DSL_EXAMPLES.md +120 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +108 -0
  7. data/{MIT-LICENSE → LICENSE} +0 -0
  8. data/README.rdoc +3 -28
  9. data/Rakefile +27 -59
  10. data/lib/relevance/core_extensions/ellipsize.rb +23 -19
  11. data/lib/relevance/core_extensions/file.rb +10 -4
  12. data/lib/relevance/core_extensions/response.rb +9 -6
  13. data/lib/relevance/core_extensions/test_case.rb +14 -12
  14. data/lib/relevance/tarantula.rb +24 -25
  15. data/lib/relevance/tarantula/attack.rb +19 -15
  16. data/lib/relevance/tarantula/attack_handler.rb +32 -26
  17. data/lib/relevance/tarantula/basic_attack.rb +36 -32
  18. data/lib/relevance/tarantula/crawler.rb +222 -216
  19. data/lib/relevance/tarantula/form.rb +27 -21
  20. data/lib/relevance/tarantula/form_submission.rb +79 -73
  21. data/lib/relevance/tarantula/html_document_handler.rb +37 -31
  22. data/lib/relevance/tarantula/html_report_helper.rb +36 -29
  23. data/lib/relevance/tarantula/html_reporter.rb +105 -99
  24. data/lib/relevance/tarantula/invalid_html_handler.rb +21 -15
  25. data/lib/relevance/tarantula/io_reporter.rb +37 -31
  26. data/lib/relevance/tarantula/link.rb +97 -73
  27. data/lib/relevance/tarantula/log_grabber.rb +20 -14
  28. data/lib/relevance/tarantula/rails_integration_proxy.rb +64 -58
  29. data/lib/relevance/tarantula/response.rb +16 -10
  30. data/lib/relevance/tarantula/result.rb +69 -63
  31. data/lib/relevance/tarantula/tidy_handler.rb +22 -17
  32. data/lib/relevance/tarantula/transform.rb +18 -14
  33. data/lib/relevance/tarantula/version.rb +5 -0
  34. data/{tasks → lib/relevance/tasks}/tarantula_tasks.rake +1 -1
  35. data/lib/tarantula-rails3.rb +9 -0
  36. data/{examples/relevance/core_extensions/ellipsize_example.rb → spec/relevance/core_extensions/ellipsize_spec.rb} +2 -2
  37. data/{examples/relevance/core_extensions/file_example.rb → spec/relevance/core_extensions/file_spec.rb} +2 -2
  38. data/{examples/relevance/core_extensions/response_example.rb → spec/relevance/core_extensions/response_spec.rb} +2 -2
  39. data/{examples/relevance/core_extensions/test_case_example.rb → spec/relevance/core_extensions/test_case_spec.rb} +1 -1
  40. data/{examples/relevance/tarantula/attack_handler_example.rb → spec/relevance/tarantula/attack_handler_spec.rb} +1 -1
  41. data/{examples/relevance/tarantula/basic_attack_example.rb → spec/relevance/tarantula/basic_attack_spec.rb} +2 -2
  42. data/{examples/relevance/tarantula/crawler_example.rb → spec/relevance/tarantula/crawler_spec.rb} +2 -2
  43. data/{examples/relevance/tarantula/form_example.rb → spec/relevance/tarantula/form_spec.rb} +2 -2
  44. data/{examples/relevance/tarantula/form_submission_example.rb → spec/relevance/tarantula/form_submission_spec.rb} +3 -3
  45. data/{examples/relevance/tarantula/html_document_handler_example.rb → spec/relevance/tarantula/html_document_handler_spec.rb} +1 -1
  46. data/{examples/relevance/tarantula/html_report_helper_example.rb → spec/relevance/tarantula/html_report_helper_spec.rb} +1 -1
  47. data/{examples/relevance/tarantula/html_reporter_example.rb → spec/relevance/tarantula/html_reporter_spec.rb} +1 -1
  48. data/{examples/relevance/tarantula/invalid_html_handler_example.rb → spec/relevance/tarantula/invalid_html_handler_spec.rb} +1 -1
  49. data/{examples/relevance/tarantula/io_reporter_example.rb → spec/relevance/tarantula/io_reporter_spec.rb} +1 -1
  50. data/{examples/relevance/tarantula/link_example.rb → spec/relevance/tarantula/link_spec.rb} +5 -5
  51. data/{examples/relevance/tarantula/log_grabber_example.rb → spec/relevance/tarantula/log_grabber_spec.rb} +1 -1
  52. data/{examples/relevance/tarantula/rails_integration_proxy_example.rb → spec/relevance/tarantula/rails_integration_proxy_spec.rb} +1 -1
  53. data/{examples/relevance/tarantula/result_example.rb → spec/relevance/tarantula/result_spec.rb} +1 -1
  54. data/{examples/relevance/tarantula/tidy_handler_example.rb → spec/relevance/tarantula/tidy_handler_spec.rb} +1 -1
  55. data/{examples/relevance/tarantula/transform_example.rb → spec/relevance/tarantula/transform_spec.rb} +2 -2
  56. data/{examples/relevance/tarantula_example.rb → spec/relevance/tarantula_spec.rb} +1 -1
  57. data/{examples/example_helper.rb → spec/spec_helper.rb} +6 -14
  58. data/tarantula.gemspec +31 -0
  59. data/template/tarantula_test.rb +1 -1
  60. data/vendor/xss-shield/MIT-LICENSE +20 -0
  61. data/vendor/xss-shield/README +76 -0
  62. data/vendor/xss-shield/init.rb +16 -0
  63. data/vendor/xss-shield/lib/xss_shield.rb +6 -0
  64. data/vendor/xss-shield/lib/xss_shield/erb_hacks.rb +111 -0
  65. data/vendor/xss-shield/lib/xss_shield/haml_hacks.rb +42 -0
  66. data/vendor/xss-shield/lib/xss_shield/safe_string.rb +47 -0
  67. data/vendor/xss-shield/lib/xss_shield/secure_helpers.rb +40 -0
  68. data/vendor/xss-shield/test/test_actionview_integration.rb +40 -0
  69. data/vendor/xss-shield/test/test_erb.rb +44 -0
  70. data/vendor/xss-shield/test/test_haml.rb +43 -0
  71. data/vendor/xss-shield/test/test_helpers.rb +25 -0
  72. data/vendor/xss-shield/test/test_safe_string.rb +55 -0
  73. metadata +170 -99
  74. data/VERSION.yml +0 -4
data/.autotest ADDED
@@ -0,0 +1,14 @@
1
+ Autotest.add_hook :initialize do |autotest|
2
+
3
+ # Check every 5 seconds
4
+ # autotest.sleep = 3
5
+
6
+ # Ignore files with suffix
7
+ %w{.svn .log .hg .git .erb .rhtml .png .txt .sh .project .rjs .rake .jpg .css .xml}.each { |exception| autotest.add_exception(exception) }
8
+
9
+ autotest.add_mapping(/relevance\/tarantula/) do |f, _|
10
+ autotest.files_matching(/^test.*rb$/)
11
+ end
12
+
13
+ end
14
+
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ rcov_tmp
2
+ tmp
3
+ pkg
4
+ rdoc
5
+ .zsh_rake_cache
6
+ doc
7
+ TAGS
8
+ coverage
9
+ *.gem
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2@tarantula
data/DSL_EXAMPLES.md ADDED
@@ -0,0 +1,120 @@
1
+ # Tarantula DSL-based API examples
2
+
3
+ I'm planning to change the Tarantula configuration API to be more
4
+ Ruby-ish, declarative and DSL-like.
5
+ This document contains examples of what I'm aiming for,
6
+ as a record of ideas and for discussion.
7
+
8
+ **This is not a promise to implement all of these features.**
9
+ I think all of these feature ideas would be useful, but I already know
10
+ some of them will be very costly and difficult to implement.
11
+ I'm including them all here because I want to come up with an API
12
+ syntax and style that will accommodate a lot of different things.
13
+
14
+ I don't yet know whether I'll maintain the current association with
15
+ test cases; it seems that it might be better to have a standalone
16
+ `tarantula_config.rb` file or something like that, with a custom
17
+ Tarantula runner that doesn't depend on test/unit or RSpec.
18
+
19
+ ## Basic crawl, starting from '/'
20
+
21
+ Tarantula.crawl
22
+
23
+ ## Basic crawl, starting from '/' and '/admin'
24
+
25
+ Tarantula.crawl('both') do |t|
26
+ t.root_page '/'
27
+ t.root_page '/admin'
28
+ end
29
+
30
+ ## Crawl with the Tidy handler
31
+
32
+ # the operand to the crawl method, if supplied, will be used
33
+ # as the tab label in the report.
34
+ Tarantula.crawl("tidy") do |t|
35
+ t.add_handler :tidy
36
+ end
37
+
38
+ ## Reorder requests on the queue
39
+
40
+ This is necessary to fix [this bug](http://github.com/relevance/tarantula/issues#issue/3)
41
+
42
+ Tarantula.crawl do |t|
43
+ # Treat the following controllers as "resourceful",
44
+ # reordering appropriately (see my comment on
45
+ # <http://github.com/relevance/tarantula/issues#issue/3>)
46
+ t.resources 'post', 'comment'
47
+
48
+ # For the 'news' controller, order the actions this way:
49
+ t.reorder_for 'news', :actions => %w{show read unread mark_read}
50
+
51
+ # For the 'history' controller, supply a comparison function:
52
+ t.reorder_for 'history', :compare => lambda{|x, y| ... }
53
+ end
54
+
55
+ (Unlike most of the declarations in this example document, these will
56
+ need to be reusable across multiple crawl blocks somehow.)
57
+
58
+ ## Selectively allowing errors
59
+
60
+ Tarantula.crawl("ignoring not-found users") do |t|
61
+ t.allow_errors :not_found, %r{/users/\d+/}
62
+ # or
63
+ t.allow_errors :not_found, :controller => 'users', :action => 'show'
64
+ end
65
+
66
+ ## Attacks
67
+
68
+ Tarantula.crawl("attacks") do |t|
69
+ t.attack :xss, :input => "<script>gotcha!</script>", :output => :input
70
+ t.attack :sql_injection, :input => "a'; DROP TABLE posts;"
71
+ t.times_to_crawl 2
72
+ end
73
+
74
+ We should have prepackaged attack suites that understand various techniques.
75
+
76
+ Tarantula.crawl("xss suite") do |t|
77
+ t.attack :xss, :suite => 'standard'
78
+ end
79
+
80
+ Tarantula.crawl("sql injection suite") do |t|
81
+ t.attack :sql_injection, :suite => 'standard'
82
+ end
83
+
84
+ ## Timeout
85
+
86
+ Tarantula.crawl do |t|
87
+ t.times_to_crawl 2
88
+ t.stop_after 2.minutes
89
+ end
90
+
91
+ ## Fuzzing
92
+
93
+ Tarantula.crawl do |t|
94
+ # :valid input uses SQL types and knowledge of model validations
95
+ # to attempt to generate valid input. You can override the defaults.
96
+ t.fuzz_with :valid_input do |f|
97
+ f.fuzz(Post, :title) { random_string(1..40) }
98
+ f.fuzz(Person, :phone) { random_string("%03d-%03d-%04d") }
99
+ end
100
+
101
+ # The point of fuzzing is to keep trying a lot of things to
102
+ # see if you can find breakage.
103
+ t.crawl_for 45.minutes
104
+ end
105
+
106
+ Tarantula.crawl do |t|
107
+ # :typed_input uses SQL types to generate "reasonable" but probably
108
+ # invalid input (e.g., numeric fields will get strings of digits,
109
+ # but they'll be too large or negative; date fields will get dates,
110
+ # but very far in the past or future; string fields will get very
111
+ # large strings.)
112
+ t.fuzz_with :typed_input
113
+ t.crawl_for 30.minutes
114
+ end
115
+
116
+ Tarantula.crawl do |t|
117
+ # :random_input just plugs in random strings everywhere.
118
+ t.fuzz_with :random_input
119
+ t.crawl_for 2.hours
120
+ end
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,108 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ relevance/tarantula (0.4.0)
5
+ hpricot (~> 0.8.4)
6
+ htmlentities (~> 4.3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ abstract (1.0.0)
12
+ actionmailer (3.0.10)
13
+ actionpack (= 3.0.10)
14
+ mail (~> 2.2.19)
15
+ actionpack (3.0.10)
16
+ activemodel (= 3.0.10)
17
+ activesupport (= 3.0.10)
18
+ builder (~> 2.1.2)
19
+ erubis (~> 2.6.6)
20
+ i18n (~> 0.5.0)
21
+ rack (~> 1.2.1)
22
+ rack-mount (~> 0.6.14)
23
+ rack-test (~> 0.5.7)
24
+ tzinfo (~> 0.3.23)
25
+ activemodel (3.0.10)
26
+ activesupport (= 3.0.10)
27
+ builder (~> 2.1.2)
28
+ i18n (~> 0.5.0)
29
+ activerecord (3.0.10)
30
+ activemodel (= 3.0.10)
31
+ activesupport (= 3.0.10)
32
+ arel (~> 2.0.10)
33
+ tzinfo (~> 0.3.23)
34
+ activeresource (3.0.10)
35
+ activemodel (= 3.0.10)
36
+ activesupport (= 3.0.10)
37
+ activesupport (3.0.10)
38
+ arel (2.0.10)
39
+ builder (2.1.2)
40
+ diff-lcs (1.1.2)
41
+ erubis (2.6.6)
42
+ abstract (>= 1.0.0)
43
+ hpricot (0.8.4)
44
+ htmlentities (4.3.0)
45
+ i18n (0.5.0)
46
+ json (1.5.3)
47
+ log_buddy (0.6.0)
48
+ mail (2.2.19)
49
+ activesupport (>= 2.3.6)
50
+ i18n (>= 0.4.0)
51
+ mime-types (~> 1.16)
52
+ treetop (~> 1.4.8)
53
+ mime-types (1.16)
54
+ mocha (0.9.12)
55
+ polyglot (0.3.2)
56
+ rack (1.2.3)
57
+ rack-mount (0.6.14)
58
+ rack (>= 1.0.0)
59
+ rack-test (0.5.7)
60
+ rack (>= 1.0)
61
+ rails (3.0.10)
62
+ actionmailer (= 3.0.10)
63
+ actionpack (= 3.0.10)
64
+ activerecord (= 3.0.10)
65
+ activeresource (= 3.0.10)
66
+ activesupport (= 3.0.10)
67
+ bundler (~> 1.0)
68
+ railties (= 3.0.10)
69
+ railties (3.0.10)
70
+ actionpack (= 3.0.10)
71
+ activesupport (= 3.0.10)
72
+ rake (>= 0.8.7)
73
+ rdoc (~> 3.4)
74
+ thor (~> 0.14.4)
75
+ rake (0.9.2)
76
+ rdiscount (1.6.8)
77
+ rdoc (3.9.2)
78
+ rspec (2.6.0)
79
+ rspec-core (~> 2.6.0)
80
+ rspec-expectations (~> 2.6.0)
81
+ rspec-mocks (~> 2.6.0)
82
+ rspec-core (2.6.4)
83
+ rspec-expectations (2.6.0)
84
+ diff-lcs (~> 1.1.2)
85
+ rspec-mocks (2.6.0)
86
+ sdoc (0.3.0)
87
+ json (>= 1.1.3)
88
+ rdoc (~> 3)
89
+ sdoc-helpers (0.1.4)
90
+ sdoc (~> 0.2)
91
+ thor (0.14.6)
92
+ treetop (1.4.10)
93
+ polyglot
94
+ polyglot (>= 0.3.1)
95
+ tzinfo (0.3.29)
96
+
97
+ PLATFORMS
98
+ ruby
99
+
100
+ DEPENDENCIES
101
+ log_buddy (~> 0.6.0)
102
+ mocha (~> 0.9.12)
103
+ rails (~> 3.0.9)
104
+ rdiscount (~> 1.6.8)
105
+ relevance/tarantula!
106
+ rspec (~> 2.6.0)
107
+ sdoc (~> 0.3.0)
108
+ sdoc-helpers (~> 0.1.4)
File without changes
data/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  == DESCRIPTION
4
4
 
5
- Tarantula is a big fuzzy spider. It crawls your Rails application, fuzzing data to see what breaks.
5
+ Tarantula is a big fuzzy spider. It crawls your Rails 3 application, fuzzing data to see what breaks.
6
6
 
7
7
  == Usage
8
8
 
@@ -11,33 +11,7 @@ Tarantula is a big fuzzy spider. It crawls your Rails application, fuzzing data
11
11
  The latest and greatest version is always available on GitHub. (See the rakefile for dependencies, or
12
12
  just let RubyGems handle it.)
13
13
 
14
- gem sources -a http://gems.github.com
15
- gem install relevance-tarantula
16
-
17
- You can also grab it from RubyForge, where we will push stable releases but may not be as bleeding edge
18
- as the GitHub gem.
19
-
20
- gem install tarantula
21
-
22
- === Project Setup
23
-
24
- To set up Tarantula into your application, add the following line into either config/environment.rb or
25
- config/environments/test.rb (preferred). This assumes that you have Rails 2.1 or higher installed.
26
-
27
- config.gem 'relevance-tarantula', :source => "http://gems.github.com", :lib => 'relevance/tarantula'
28
-
29
- Since Rails doesn't (yet) support automatically loading rake tasks that live inside gems, you will need
30
- to update your Rakefile to load Tarantula's rake tasks. The simplest approach is to start by vendoring
31
- Tarantula into your Rails app.
32
-
33
- mkdir -p vendor/gems
34
- cd vendor/gems
35
- gem unpack relevance-tarantula
36
-
37
- You can then add the following line into your Rakefile, which will allow your application to discover
38
- Tarantula's rake tasks.
39
-
40
- load File.join(RAILS_ROOT, Dir["vendor/gems/relevance-tarantula-*/tasks/*.rake"])
14
+ gem install tarantula-rails3
41
15
 
42
16
  === Crawling Your App
43
17
 
@@ -51,6 +25,7 @@ Take a moment to familiarize yourself with the generated test. If parts of your
51
25
  login, update the test to make sure Tarantula can access those parts of your app.
52
26
 
53
27
  require "relevance/tarantula"
28
+ require "test_helper"
54
29
 
55
30
  class TarantulaTest < ActionController::IntegrationTest
56
31
  # Load enough test data to ensure that there's a link to every page in your
data/Rakefile CHANGED
@@ -1,72 +1,40 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
3
  require 'rake/rdoctask'
4
- require 'micronaut'
5
- require 'micronaut/rake_task'
6
4
 
7
5
  begin
8
- require 'jeweler'
9
- files = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "VERSION.yml"]
10
- files << Dir["examples/**/*", "laf/**/*", "lib/**/*", "tasks/**/*", "template/**/*"]
11
-
12
- Jeweler::Tasks.new do |s|
13
- s.name = "tarantula"
14
- s.summary = "A big hairy fuzzy spider that crawls your site, wreaking havoc"
15
- s.description = "A big hairy fuzzy spider that crawls your site, wreaking havoc"
16
- s.homepage = "http://github.com/relevance/tarantula"
17
- s.email = "opensource@thinkrelevance.com"
18
- s.authors = ["Relevance, Inc."]
19
- s.require_paths = ["lib"]
20
- s.files = files.flatten
21
- s.add_dependency 'htmlentities'
22
- s.add_dependency 'hpricot'
23
- s.rubyforge_project = 'thinkrelevance'
24
- end
25
- rescue LoadError
26
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
27
- end
28
-
29
- desc 'Generate documentation for the tarantula plugin.'
30
- Rake::RDocTask.new(:rdoc) do |rdoc|
31
- rdoc.rdoc_dir = 'rdoc'
32
- rdoc.title = 'Tarantula'
33
- rdoc.options << '--line-numbers' << '--inline-source'
34
- rdoc.rdoc_files.include('README.rdoc')
35
- rdoc.rdoc_files.include('lib/**/*.rb')
36
- end
6
+ require 'rspec'
7
+ require 'rspec/core/rake_task'
37
8
 
38
- desc "Run all micronaut examples"
39
- Micronaut::RakeTask.new :examples do |t|
40
- t.pattern = "examples/**/*_example.rb"
41
- end
9
+ RSpec::Core::RakeTask.new('spec') do |t|
10
+ t.verbose = true
11
+ end
42
12
 
43
- namespace :examples do
44
- desc "Run all micronaut examples using rcov"
45
- Micronaut::RakeTask.new :coverage do |t|
46
- t.pattern = "examples/**/*_example.rb"
13
+ desc "Run all RSpec specs using rcov"
14
+ RSpec::Core::RakeTask.new :rcov do |t|
15
+ t.pattern = File.dirname(__FILE__)+"/spec/**/*_spec.rb"
47
16
  t.rcov = true
48
17
  t.rcov_opts = %[--exclude "gems/*,/Library/Ruby/*,config/*" --text-summary --sort coverage]
49
18
  end
50
-
51
- RAILS_VERSIONS = %w[2.3.2 2.3.4]
52
-
53
- unless RUBY_VERSION =~ /^1\.9\./
54
- RAILS_VERSIONS.unshift(*%w[2.0.2 2.1.0 2.1.1 2.2.2 2.3.3])
55
- RAILS_VERSIONS.sort!
56
- end
57
-
58
- desc "Run examples with multiple versions of rails"
59
- task :multi_rails do
60
- RAILS_VERSIONS.each do |rails_version|
61
- puts
62
- sh "RAILS_VERSION='#{rails_version}' rake examples"
63
- end
64
- end
65
-
19
+
20
+ task :default => :spec
21
+ rescue LoadError
22
+ puts "rspec, or one of its dependencies, is not available. Install it with: sudo gem install rspec"
66
23
  end
67
24
 
68
- if ENV["RUN_CODE_RUN"]
69
- task :default => "examples:multi_rails"
70
- else
71
- task :default => "examples"
25
+ begin
26
+ %w{sdoc sdoc-helpers rdiscount}.each { |name| gem name }
27
+ require 'sdoc_helpers'
28
+ rescue LoadError => ex
29
+ puts "sdoc support not enabled:"
30
+ puts ex.inspect
31
+ end
32
+
33
+ require 'rake/rdoctask'
34
+ Rake::RDocTask.new do |rdoc|
35
+ version = File.exist?('VERSION') ? File.read('VERSION') : ''
36
+ rdoc.rdoc_dir = 'rdoc'
37
+ rdoc.title = "tarantula #{version}"
38
+ rdoc.rdoc_files.include('README*')
39
+ rdoc.rdoc_files.include('lib/**/*.rb')
72
40
  end
@@ -1,22 +1,26 @@
1
- module Relevance::CoreExtensions::Nil
2
- def ellipsize(cutoff = 20)
3
- ""
4
- end
5
- end
1
+ module Relevance
2
+ module CoreExtensions
3
+ module Nil
4
+ def ellipsize(cutoff = 20)
5
+ ""
6
+ end
7
+ end
6
8
 
7
- module Relevance::CoreExtensions::String
8
- def ellipsize(cutoff = 20)
9
- if length > cutoff
10
- "#{self[0...cutoff]}..."
11
- else
12
- self
9
+ module String
10
+ def ellipsize(cutoff = 20)
11
+ if length > cutoff
12
+ "#{self[0...cutoff]}..."
13
+ else
14
+ self
15
+ end
16
+ end
17
+ end
18
+
19
+ module Object
20
+ def ellipsize(cutoff = 20)
21
+ inspect.ellipsize(cutoff)
22
+ end
13
23
  end
14
- end
15
- end
16
-
17
- module Relevance::CoreExtensions::Object
18
- def ellipsize(cutoff = 20)
19
- inspect.ellipsize(cutoff)
20
24
  end
21
25
  end
22
26
 
@@ -29,6 +33,6 @@ end
29
33
  class NilClass
30
34
  include Relevance::CoreExtensions::Nil
31
35
  end
32
-
33
-
36
+
37
+
34
38