blundersaur 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document CHANGED
@@ -1,5 +1,5 @@
1
- README.rdoc
2
1
  lib/**/*.rb
3
2
  bin/*
3
+ -
4
4
  features/**/*.feature
5
- LICENSE
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.5.2"
11
+ gem "rcov", ">= 0"
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.5.2)
6
+ bundler (~> 1.0.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ rake (0.8.7)
10
+ rcov (0.9.9)
11
+ rcov (0.9.9-java)
12
+
13
+ PLATFORMS
14
+ java
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ bundler (~> 1.0.0)
19
+ jeweler (~> 1.5.2)
20
+ rcov
File without changes
data/README.rdoc CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  Blundersaur is a library of Ruby methods to simulate data entry mistakes.
4
4
 
5
+ == Installation
6
+
7
+ gem install blundersaur
8
+
9
+ == Usage
10
+
11
+ require 'rubygems'
12
+ require 'blundersaur'
13
+
14
+ "There's a snake in my boots!".random_mistake
15
+
5
16
  == Note on Patches/Pull Requests
6
17
 
7
18
  * Fork the project.
data/Rakefile CHANGED
@@ -1,21 +1,30 @@
1
1
  require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
2
10
  require 'rake'
3
11
 
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "blundersaur"
8
- gem.summary = %Q{A library of Ruby methods to simulate data entry mistakes}
9
- gem.description = %Q{A library of Ruby methods to simulate data entry mistakes}
10
- gem.email = "viking415@gmail.com"
11
- gem.homepage = "http://github.com/viking/blundersaur"
12
- gem.authors = ["Jeremy Stephens"]
13
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
- end
15
- Jeweler::GemcutterTasks.new
16
- rescue LoadError
17
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "blundersaur"
16
+ gem.homepage = "https://github.com/viking/blundersaur"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{A library of Ruby methods to simulate data entry mistakes}
19
+ gem.description = %Q{A library of Ruby methods to simulate data entry mistakes}
20
+ gem.email = "viking@pillageandplunder.net"
21
+ gem.authors = ["Jeremy Stephens"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
18
26
  end
27
+ Jeweler::RubygemsDotOrgTasks.new
19
28
 
20
29
  require 'rake/testtask'
21
30
  Rake::TestTask.new(:test) do |test|
@@ -24,21 +33,13 @@ Rake::TestTask.new(:test) do |test|
24
33
  test.verbose = true
25
34
  end
26
35
 
27
- begin
28
- require 'rcov/rcovtask'
29
- Rcov::RcovTask.new do |test|
30
- test.libs << 'test'
31
- test.pattern = 'test/**/test_*.rb'
32
- test.verbose = true
33
- end
34
- rescue LoadError
35
- task :rcov do
36
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
- end
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/test_*.rb'
40
+ test.verbose = true
38
41
  end
39
42
 
40
- task :test => :check_dependencies
41
-
42
43
  task :default => :test
43
44
 
44
45
  require 'rake/rdoctask'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.0.1
data/blundersaur.gemspec CHANGED
@@ -22,8 +22,6 @@ Gem::Specification.new do |s|
22
22
  "LICENSE",
23
23
  "README.rdoc",
24
24
  "Rakefile",
25
- "VERSION",
26
- "blundersaur.gemspec",
27
25
  "lib/blundersaur.rb",
28
26
  "lib/blundersaur/extensions.rb",
29
27
  "lib/blundersaur/extensions/string.rb",
@@ -1,38 +1,156 @@
1
1
  module Blundersaur
2
2
  module Extensions
3
3
  module String
4
+ MISTAKE_METHODS = [:fat_finger!, :stutter!, :mistype!, :phonetic_swap!, :transpose!]
5
+ PHONETIC_GROUPS = [
6
+ # whole words
7
+ ["your", "you're"],
8
+ ["there", "their", "they're"],
9
+ nil,
10
+
11
+ # syllables
12
+ ["ph", "f"]
13
+ ]
14
+
15
+ def index_of_random_letter
16
+ indices = (0...length).sort { |a, b| rand(3) - 1 }
17
+ index = indices.shift
18
+ while index && self[index..index] =~ /\W/
19
+ index = indices.shift
20
+ end
21
+ index
22
+ end
23
+
4
24
  def fat_finger!
5
- i = rand(self.length)
6
- chars = Keyboards::Qwerty.keys_near(self[i])
7
- char = chars[rand(chars.length)]
8
- self[i..i] = (rand(2) == 1 ? [self[i], char] : [char, self[i]]).pack("cc")
25
+ index = index_of_random_letter
26
+ if index
27
+ chars = Keyboards::Qwerty.keys_near(self[index..index])
28
+ char = chars[rand(chars.length)]
29
+ self[index..index] = rand(2) == 1 ? self[index..index] + char : char + self[index..index]
30
+ end
9
31
  self
10
32
  end
11
33
 
12
34
  def fat_finger
13
- self.dup.fat_finger!
35
+ dup.fat_finger!
14
36
  end
15
37
 
16
38
  def stutter!
17
- i = rand(self.length)
18
- self[i..i] = self[i..i] * 2
39
+ i = rand(length)
40
+ self[i] = self[i] * 2
19
41
  self
20
42
  end
21
43
 
22
44
  def stutter
23
- self.dup.stutter!
45
+ dup.stutter!
24
46
  end
25
47
 
26
48
  def mistype!
27
- i = rand(self.length)
28
- chars = Keyboards::Qwerty.keys_near(self[i])
29
- char = chars[rand(chars.length)]
30
- self[i] = char
49
+ index = index_of_random_letter
50
+ if index
51
+ chars = Keyboards::Qwerty.keys_near(self[index..index])
52
+ char = chars[rand(chars.length)]
53
+ self[index..index] = char
54
+ end
31
55
  self
32
56
  end
33
57
 
34
58
  def mistype
35
- self.dup.mistype!
59
+ dup.mistype!
60
+ end
61
+
62
+ def random_mistake!
63
+ send(MISTAKE_METHODS[rand(MISTAKE_METHODS.length)])
64
+ end
65
+
66
+ def random_mistake
67
+ dup.random_mistake!
68
+ end
69
+
70
+ # This method is kind of expensive :(
71
+ def phonetic_swap!(passes = 1)
72
+ # Find all of the matches in the string
73
+ # NOTE: if passes == 1, it would probably be better to sort the groups
74
+ # randomly and stop at the first one we find that has a match
75
+ matches = {}
76
+ whole_words = true
77
+ PHONETIC_GROUPS.each_with_index do |group, index|
78
+ if group.nil?
79
+ whole_words = false
80
+ next
81
+ end
82
+ re_str = "(?:#{group.join('|')})"
83
+ re = Regexp.new(whole_words ? '\b'+re_str+'\b' : re_str, 'i')
84
+
85
+ matches[index] = []
86
+ scan(re) do |str|
87
+ matches[index] << [$~.begin(0), str]
88
+ end
89
+ matches.delete(index) if matches[index].empty?
90
+ end
91
+
92
+ if !matches.empty?
93
+ adjustments = []
94
+ passes.times do |i|
95
+ # Pick a random group's matches
96
+ group_index = matches.keys[rand(matches.keys.length)]
97
+ group_matches = matches[group_index]
98
+ group = PHONETIC_GROUPS[group_index]
99
+
100
+ # Pick a random match to replace
101
+ offset, string = group_matches.delete_at(rand(group_matches.length))
102
+ taken_index = group.index(string.downcase)
103
+ matches.delete(group_index) if group_matches.empty?
104
+
105
+ # Adjust offset if necessary
106
+ new_offset = adjustments.inject(offset) do |n, (a_offset, a_diff)|
107
+ offset > a_offset ? n + a_diff : n
108
+ end
109
+ offset = new_offset
110
+
111
+ # Pick a random string from the group to replace it with
112
+ elt_indices = (0...group.length).sort { |a, b| rand(3) - 1 }
113
+ elt_index = elt_indices.shift
114
+ elt_index = elt_indices.shift if elt_index == taken_index
115
+ replacement = group[elt_index].dup
116
+
117
+ # Add adjustment for further iterations
118
+ diff = replacement.length - string.length
119
+ if diff != 0
120
+ adjustments << [offset, diff]
121
+ end
122
+
123
+ # Match case of string in replacement
124
+ len = diff < 0 ? replacement.length : string.length
125
+ len.times do |i|
126
+ ord = string[i].ord
127
+ replacement[i] = replacement[i].upcase if ord >= 65 && ord <= 90
128
+ end
129
+
130
+ # Booyah!
131
+ self[offset, string.length] = replacement
132
+
133
+ break if matches.empty?
134
+ end
135
+ end
136
+ self
137
+ end
138
+
139
+ def phonetic_swap(passes = 1)
140
+ dup.phonetic_swap!(passes)
141
+ end
142
+
143
+ def transpose!
144
+ if length > 1
145
+ i = rand(length-1)
146
+ r = i..(i+1)
147
+ self[r] = self[r].reverse
148
+ end
149
+ self
150
+ end
151
+
152
+ def transpose
153
+ dup.transpose!
36
154
  end
37
155
  end
38
156
  end
@@ -2,13 +2,16 @@ module Blundersaur
2
2
  module Keyboards
3
3
  module Qwerty
4
4
  ROWS = [
5
- nil, ?q, ?w, ?e, ?r, ?t, ?y, ?u, ?i, ?o, ?p, nil,
6
- nil, ?a, ?s, ?d, ?f, ?g, ?h, ?j, ?k, ?l, nil,
7
- nil, ?z, ?x, ?c, ?v, ?b, ?n, ?m, nil
5
+ nil, "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", nil,
6
+ nil, "a", "s", "d", "f", "g", "h", "j", "k", "l", nil,
7
+ nil, "z", "x", "c", "v", "b", "n", "m", nil
8
8
  ]
9
9
  def self.keys_near(char)
10
- i = ROWS.index(char)
11
- ROWS.values_at(i-1, i+1).compact
10
+ upcased = char.ord < 97
11
+ i = ROWS.index(char.downcase)
12
+ keys = ROWS.values_at(i-1, i+1).compact
13
+ keys.collect!(&:upcase) if upcased
14
+ keys
12
15
  end
13
16
  end
14
17
  end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "..", "..", "helper")
1
+ require 'helper'
2
2
 
3
3
  module Blundersaur
4
4
  module Extensions
@@ -13,6 +13,13 @@ module Blundersaur
13
13
  assert_match /^[gj]?h[gj]?[wr]?e[wr]?k?lk?k?lk?[ip]?o[ip]?$/, result
14
14
  end
15
15
 
16
+ def test_fat_finger_skips_spaces
17
+ str = " hey "
18
+ 50.times do
19
+ assert_not_equal str, str.fat_finger
20
+ end
21
+ end
22
+
16
23
  def test_stutter
17
24
  result = "hello".stutter
18
25
  assert_not_equal result, "hello"
@@ -24,6 +31,76 @@ module Blundersaur
24
31
  assert_not_equal result, "hello"
25
32
  assert_match /^[gjh][wre][kl][kl][ipo]$/, result
26
33
  end
34
+
35
+ def test_mistype_skips_spaces
36
+ str = " hey "
37
+ 50.times do
38
+ assert_not_equal str, str.mistype
39
+ end
40
+ end
41
+
42
+ def test_random_mistake
43
+ str = "hey there mister"
44
+ 50.times do
45
+ assert_not_equal str, str.random_mistake
46
+ end
47
+ end
48
+
49
+ def test_phonetic_swap_your_youre
50
+ assert ["you're pants are burning; you're a liar", "your pants are burning; your a liar"].include?("your pants are burning; you're a liar".phonetic_swap)
51
+ assert_equal "your the man", "you're the man".phonetic_swap
52
+ end
53
+
54
+ def test_phonetic_swap_ph_f
55
+ assert_equal "phunky town", "funky town".phonetic_swap
56
+ end
57
+
58
+ def test_phonetic_swap_there_their_theyre
59
+ assert %w{there their}.include?("they're".phonetic_swap)
60
+ assert %w{they're their}.include?("there".phonetic_swap)
61
+ assert %w{there they're}.include?("their".phonetic_swap)
62
+ end
63
+
64
+ def test_phonetic_swap_handles_word_case
65
+ result = "There".phonetic_swap
66
+ assert_not_equal "There", result
67
+ assert_equal "T", result[0..0]
68
+ end
69
+
70
+ def test_phonetic_swap_nothing
71
+ str = "nothing"
72
+ assert_equal str, str.phonetic_swap
73
+ end
74
+
75
+ def test_phonetic_swap_multiple_passes
76
+ assert_equal "your spilling dip on you're pants", "you're spilling dip on your pants".phonetic_swap(2)
77
+ assert_equal "you're your you're your you're your you're your", "your you're your you're your you're your you're".phonetic_swap(8)
78
+ end
79
+
80
+ def test_phonetic_swap_uses_random_match
81
+ counts = [0, 0, 0]
82
+ str = "your you're your"
83
+ 50.times do |i|
84
+ case str.phonetic_swap
85
+ when "you're you're your" then counts[0] += 1
86
+ when "your your your" then counts[1] += 1
87
+ when "your you're you're" then counts[2] += 1
88
+ end
89
+ end
90
+ assert counts[0] > 0, %{"you're you're your" wasn't ever created}
91
+ assert counts[1] > 0, %{"your your your" wasn't ever created}
92
+ assert counts[2] > 0, %{"your you're you're" wasn't ever created}
93
+ end
94
+
95
+ def test_transpose
96
+ str = "hey"
97
+ results = %w{ehy hye}
98
+ 20.times do
99
+ assert results.include?(str.transpose)
100
+ end
101
+ assert_equal "h", "h".transpose
102
+ assert_equal "", "".transpose
103
+ end
27
104
  end
28
105
  end
29
106
  end
@@ -1,39 +1,40 @@
1
- require File.join(File.dirname(__FILE__), "..", "..", "helper")
1
+ require 'helper'
2
2
 
3
3
  module Blundersaur
4
4
  module Keyboards
5
5
  class TestQwerty < Test::Unit::TestCase
6
6
  def test_keys_near
7
7
  expected = {
8
- ?q => [?w],
9
- ?w => [?q, ?e],
10
- ?e => [?w, ?r],
11
- ?r => [?e, ?t],
12
- ?t => [?r, ?y],
13
- ?y => [?t, ?u],
14
- ?u => [?y, ?i],
15
- ?i => [?u, ?o],
16
- ?o => [?i, ?p],
17
- ?p => [?o],
18
- ?a => [?s],
19
- ?s => [?a, ?d],
20
- ?d => [?s, ?f],
21
- ?f => [?d, ?g],
22
- ?g => [?f, ?h],
23
- ?h => [?g, ?j],
24
- ?j => [?h, ?k],
25
- ?k => [?j, ?l],
26
- ?l => [?k],
27
- ?z => [?x],
28
- ?x => [?z, ?c],
29
- ?c => [?x, ?v],
30
- ?v => [?c, ?b],
31
- ?b => [?v, ?n],
32
- ?n => [?b, ?m],
33
- ?m => [?n]
8
+ "q" => ["w"],
9
+ "w" => ["q", "e"],
10
+ "e" => ["w", "r"],
11
+ "r" => ["e", "t"],
12
+ "t" => ["r", "y"],
13
+ "y" => ["t", "u"],
14
+ "u" => ["y", "i"],
15
+ "i" => ["u", "o"],
16
+ "o" => ["i", "p"],
17
+ "p" => ["o"],
18
+ "a" => ["s"],
19
+ "s" => ["a", "d"],
20
+ "d" => ["s", "f"],
21
+ "f" => ["d", "g"],
22
+ "g" => ["f", "h"],
23
+ "h" => ["g", "j"],
24
+ "j" => ["h", "k"],
25
+ "k" => ["j", "l"],
26
+ "l" => ["k"],
27
+ "z" => ["x"],
28
+ "x" => ["z", "c"],
29
+ "c" => ["x", "v"],
30
+ "v" => ["c", "b"],
31
+ "b" => ["v", "n"],
32
+ "n" => ["b", "m"],
33
+ "m" => ["n"]
34
34
  }
35
35
  expected.each_pair do |char, set|
36
36
  assert_equal set, Qwerty.keys_near(char)
37
+ assert_equal set.collect(&:upcase), Qwerty.keys_near(char.upcase)
37
38
  end
38
39
  end
39
40
  end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "..", "helper")
1
+ require 'helper'
2
2
 
3
3
  module Blundersaur
4
4
  class TestExtensions < Test::Unit::TestCase
data/test/helper.rb CHANGED
@@ -1,6 +1,15 @@
1
1
  require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
2
10
  require 'test/unit'
3
11
 
12
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
13
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
14
  require 'blundersaur'
6
15
 
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "helper")
1
+ require 'helper'
2
2
 
3
3
  class TestBlundersaur < Test::Unit::TestCase
4
4
  def test_truth
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blundersaur
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
5
10
  platform: ruby
6
11
  authors:
7
12
  - Jeremy Stephens
@@ -9,23 +14,66 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-02-03 00:00:00 -06:00
17
+ date: 2011-02-16 00:00:00 -06:00
13
18
  default_executable:
14
- dependencies: []
15
-
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: bundler
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 0
30
+ - 0
31
+ version: 1.0.0
32
+ type: :development
33
+ prerelease: false
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: jeweler
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 1
44
+ - 5
45
+ - 2
46
+ version: 1.5.2
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rcov
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: *id003
16
63
  description: A library of Ruby methods to simulate data entry mistakes
17
- email: viking415@gmail.com
64
+ email: viking@pillageandplunder.net
18
65
  executables: []
19
66
 
20
67
  extensions: []
21
68
 
22
69
  extra_rdoc_files:
23
- - LICENSE
70
+ - LICENSE.txt
24
71
  - README.rdoc
25
72
  files:
26
73
  - .document
27
- - .gitignore
28
- - LICENSE
74
+ - Gemfile
75
+ - Gemfile.lock
76
+ - LICENSE.txt
29
77
  - README.rdoc
30
78
  - Rakefile
31
79
  - VERSION
@@ -42,36 +90,41 @@ files:
42
90
  - test/helper.rb
43
91
  - test/test_blundersaur.rb
44
92
  has_rdoc: true
45
- homepage: http://github.com/viking/blundersaur
46
- licenses: []
47
-
93
+ homepage: https://github.com/viking/blundersaur
94
+ licenses:
95
+ - MIT
48
96
  post_install_message:
49
- rdoc_options:
50
- - --charset=UTF-8
97
+ rdoc_options: []
98
+
51
99
  require_paths:
52
100
  - lib
53
101
  required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
54
103
  requirements:
55
104
  - - ">="
56
105
  - !ruby/object:Gem::Version
106
+ hash: 326574642416581493
107
+ segments:
108
+ - 0
57
109
  version: "0"
58
- version:
59
110
  required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
60
112
  requirements:
61
113
  - - ">="
62
114
  - !ruby/object:Gem::Version
115
+ segments:
116
+ - 0
63
117
  version: "0"
64
- version:
65
118
  requirements: []
66
119
 
67
120
  rubyforge_project:
68
- rubygems_version: 1.3.5
121
+ rubygems_version: 1.3.7
69
122
  signing_key:
70
123
  specification_version: 3
71
124
  summary: A library of Ruby methods to simulate data entry mistakes
72
125
  test_files:
73
- - test/blundersaur/test_extensions.rb
74
126
  - test/blundersaur/extensions/test_string.rb
75
127
  - test/blundersaur/keyboards/test_qwerty.rb
128
+ - test/blundersaur/test_extensions.rb
76
129
  - test/helper.rb
77
130
  - test/test_blundersaur.rb
data/.gitignore DELETED
@@ -1,21 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC