array_statistics 0.1.0

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.
@@ -0,0 +1,4 @@
1
+ == 0.1.0 2008-10-30
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -0,0 +1,18 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ config/website.yml.sample
7
+ lib/array_statistics.rb
8
+ script/console
9
+ script/destroy
10
+ script/generate
11
+ script/txt2html
12
+ test/test_array_statistics.rb
13
+ test/test_helper.rb
14
+ website/index.html
15
+ website/index.txt
16
+ website/javascripts/rounded_corners_lite.inc.js
17
+ website/stylesheets/screen.css
18
+ website/template.html.erb
@@ -0,0 +1,6 @@
1
+
2
+ For more information on array_statistics, see http://rubyforge.org/projects/array-statistic/
3
+
4
+
5
+
6
+
@@ -0,0 +1,55 @@
1
+ = array_statistics
2
+
3
+ http://rubyforge.org/projects/array-statistic/
4
+
5
+ == DESCRIPTION:
6
+
7
+ Array Statistics adds statistical operations to the ruby Array class.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * Percentiles
12
+ * Quartiles
13
+ * Median
14
+ * Mean
15
+ * Sum
16
+ * Outliers
17
+
18
+ == SYNOPSIS:
19
+
20
+ Array Statistics adds statistical operations to the ruby Array class.
21
+ The operations work on arrays of numbers or, more interestingly, arrays of _things_.
22
+ Each method added to Array by this gem takes an optional block that defines the "value" on which to base the operation.
23
+
24
+ == REQUIREMENTS:
25
+
26
+ meh
27
+
28
+ == INSTALL:
29
+
30
+ sudo gem install array-statistics
31
+
32
+ == LICENSE:
33
+
34
+ (The MIT License)
35
+
36
+ Copyright (c) 2008 Bruce Goodwin
37
+
38
+ Permission is hereby granted, free of charge, to any person obtaining
39
+ a copy of this software and associated documentation files (the
40
+ 'Software'), to deal in the Software without restriction, including
41
+ without limitation the rights to use, copy, modify, merge, publish,
42
+ distribute, sublicense, and/or sell copies of the Software, and to
43
+ permit persons to whom the Software is furnished to do so, subject to
44
+ the following conditions:
45
+
46
+ The above copyright notice and this permission notice shall be
47
+ included in all copies or substantial portions of the Software.
48
+
49
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
50
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
51
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
52
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
53
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
54
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
55
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,26 @@
1
+ %w[rubygems rake rake/clean fileutils hoe newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/array_statistics'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('array_statistics', ArrayStatistics::VERSION) do |p|
7
+ p.developer('Bruce Goodwin', 'rubybg@gmail.com')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
10
+ p.rubyforge_name = p.name # TODO this is default value
11
+ # p.extra_deps = [
12
+ # ['activesupport','>= 2.0.2'],
13
+ # ]
14
+ p.extra_dev_deps = [
15
+ ['newgem', ">= #{::Newgem::VERSION}"]
16
+ ]
17
+
18
+ p.spec_extras['rdoc_options'] = ['--main', Dir['README*'].first] # hopefully fixed in future hoe > 1.8
19
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
20
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
21
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
22
+ p.rsync_args = '-av --delete --ignore-errors'
23
+ end
24
+
25
+ require 'newgem/tasks' # load /tasks/*.rake
26
+
@@ -0,0 +1,2 @@
1
+ host: unknown@rubyforge.org
2
+ remote_dir: /var/www/gforge-projects/array_statistics
@@ -0,0 +1,331 @@
1
+
2
+ # no need for these yet... maybe later.
3
+ # $:.unshift(File.dirname(__FILE__)) unless
4
+ # $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
5
+
6
+ module ArrayStatistics
7
+ VERSION = '0.1.0'
8
+ end
9
+ class Array
10
+ @as_sort_dirty = true
11
+ @as_last_comparison_block = nil
12
+
13
+ # Get percent order statistic based on "order statistic" from here: http://mathworld.wolfram.com/topics/RankStatistics.html
14
+ # Given some percentage between 0 and 1 (inclusive) return the greatest value in the subarray of this array which contains
15
+ # the bottom percent_less_than values of this array.
16
+ #
17
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
18
+ # This block can be safely skipped if the array contains numbers.
19
+ def percentile(percent_less_than, &value_block) # :yields: element
20
+ value_block = proc{|element| element} unless block_given?
21
+ sort! do |x, y|
22
+ value_block.call(x) <=> value_block.call(y)
23
+ end
24
+
25
+ percent_less_than = 0 if percent_less_than < 0
26
+ return nil if percent_less_than == 0
27
+ percent_less_than = 1 if percent_less_than > 1
28
+ percentile_i = (percent_less_than * (length-1)).floor
29
+ return self[percentile_i]
30
+ end
31
+
32
+ # Get percent rank based on "statistical rank" from here:http://mathworld.wolfram.com/topics/RankStatistics.html
33
+ # Given some value, find the percentage of its rank in this array
34
+ # the number returned will be the number between 0 and 1 (inclusive) which represents the percentage of values
35
+ # in this array which are less than or equal to the value passed in.
36
+ #
37
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
38
+ # This block can be safely skipped if the array contains numbers.
39
+ def percentile_rank(value, &value_block) # :yields: element
40
+ value_block = proc{|element| element} unless block_given?
41
+ sort! do |x, y|
42
+ value_block.call(x) <=> value_block.call(y)
43
+ end
44
+ return 0.0 if value < value_block.call(self[0])
45
+ each_index do |i|
46
+ if(value_block.call(self[i]) > value)
47
+
48
+ return i.to_f/length
49
+ end
50
+ end
51
+ return 1
52
+ end
53
+
54
+ # Get the median value of this array.
55
+ #
56
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
57
+ # This block can be safely skipped if the array contains numbers.
58
+ def median(sort_required=true, &value_block) # :yields: element
59
+ return 0 if empty? #to reduce instances of calling math methods on nil.
60
+ value_block = proc{|element| element} unless block_given?
61
+
62
+ median_index_arr = median_indices(&value_block)
63
+ median_vals = median_index_arr.collect do |element_index|
64
+ value_block.call(self[element_index])
65
+ end
66
+
67
+ median_vals.average
68
+ end
69
+
70
+ # returns either a single or double-value array containing the index or surrounding indeces
71
+ #
72
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
73
+ # This block can be safely skipped if the array contains numbers.
74
+ def median_indices(sort_required=true, &value_block) # :yields: element
75
+ return 0 if length == 0
76
+ value_block = proc{|element| element} unless block_given?
77
+ if(sort_required)
78
+ sort! do |x, y|
79
+ value_block.call(x) <=> value_block.call(y)
80
+ end
81
+ end
82
+
83
+ median_index_arr = [length / 2]
84
+ if(length % 2 == 0)
85
+ median_index_arr.unshift(median_index_arr[0]-1)
86
+ end
87
+
88
+ median_index_arr
89
+ end
90
+
91
+ #returns an array with 2 values. The values are the first and third quartile indices following the same rules as the results of the median_indices method
92
+ #
93
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
94
+ # This block can be safely skipped if the array contains numbers.
95
+ def quartile_indices(&value_block) # :yields: element
96
+ median_i = median_indices(&value_block)
97
+ low_end = median_i[0]
98
+ high_start = median_i[median_i.length() -1]
99
+
100
+ low_arr = self[0..low_end]
101
+ high_arr = self[high_start..-1]
102
+
103
+ q1_indices = low_arr.median_indices(false, &value_block)
104
+ q3_indices = high_arr.median_indices(false, &value_block)
105
+ q3_indices.collect! do |index|
106
+ index + high_start
107
+ end
108
+ return [q1_indices, q3_indices]
109
+ end
110
+
111
+ #returns an array containing all the outliers in this set
112
+ #
113
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
114
+ # This block can be safely skipped if the array contains numbers.
115
+ def outliers(quartile_range_factor=1.5, &value_block) # :yields: element
116
+ value_block = proc{|element| element} unless block_given?
117
+ outlier_arr = []
118
+ outlier_threshold_is = outlier_threshold_indices(quartile_range_factor, &value_block)
119
+ # puts("Outlier Thresholds Indeces = [#{outlier_threshold_is[0]} <=> #{outlier_threshold_is[1]}]")
120
+ outlier_arr << self[0..outlier_threshold_is[0]] unless outlier_threshold_is[0].nil?
121
+ # puts("upper outliers = #{self[outlier_threshold_is[1]..-1] }")
122
+ outlier_arr << self[outlier_threshold_is[1]..-1] unless outlier_threshold_is[1].nil?
123
+ return outlier_arr.flatten
124
+ end
125
+
126
+ #removes all the outliers from this set and returns them.
127
+ #
128
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
129
+ # This block can be safely skipped if the array contains numbers.
130
+ def remove_outliers!(quartile_range_factor=1.5, &value_block) # :yields: element
131
+ outlier_arr = []
132
+ outlier_threshold_is = outlier_threshold_indices(quartile_range_factor, &value_block)
133
+
134
+ outlier_arr = outlier_arr + self.slice!(0..outlier_threshold_is[0]) unless outlier_threshold_is[0].nil?
135
+ #the preceeding slice!() will, of course shift the upper outlier threshold index down
136
+ high_outlier_index_offset = (outlier_threshold_is[0].nil?)? 0 : outlier_threshold_is[0] + 1
137
+ outlier_arr = outlier_arr + self.slice!(outlier_threshold_is[1]-high_outlier_index_offset..-1) unless outlier_threshold_is[1].nil?
138
+ return outlier_arr
139
+ end
140
+
141
+ # Returns an array with two values.
142
+ # The first value is the index of the last low outlier in this sorted array (this array will be sorted as a side-effect of this method)
143
+ # or nil if there are no low-end outliers
144
+ # The second value is the index of the first high outlier in this sorted array or nil if there are no high-end outliers
145
+ #
146
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
147
+ # This block can be safely skipped if the array contains numbers.
148
+ def outlier_threshold_indices(quartile_range_factor=1.5, &value_block) # :yields: element
149
+ value_block = proc{|element| element} unless block_given?
150
+ thresholds = outlier_thresholds(quartile_range_factor, &value_block) #this sorts self!
151
+ low_index = -1
152
+ while(value_block.call(self[low_index +1] ) < thresholds[0]) do
153
+ low_index = low_index + 1
154
+ end
155
+ low_index = nil if(low_index == -1)
156
+
157
+ high_index = length
158
+ while(value_block.call(self[high_index -1] ) > thresholds[1]) do
159
+ high_index = high_index - 1
160
+ end
161
+ high_index = nil if(high_index == length)
162
+ return [low_index, high_index]
163
+ end
164
+
165
+ #returns an array with two values:
166
+ # The first value is the low outlier threshhold for this data set
167
+ # The second value is the high outlier threshhold for this data set
168
+ #
169
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
170
+ # This block can be safely skipped if the array contains numbers.
171
+ def outlier_thresholds(quartile_range_factor=1.5, &value_block) # :yields: element
172
+ value_block = proc{|element| element} unless block_given?
173
+
174
+ quartile_is = quartile_indices(&value_block)
175
+ q1 = quartile_is[0].collect do |element_index|
176
+ value_block.call(self[element_index])
177
+ end
178
+ q1 = q1.average
179
+
180
+ q3 = quartile_is[1].collect do |element_index|
181
+ value_block.call(self[element_index])
182
+ end
183
+ q3 = q3.average
184
+
185
+ interquartile_range = q3-q1
186
+ # puts("Interquartile Range = [#{q1} <=> #{q3}], quartile range factor: #{quartile_range_factor}")
187
+ low_outlier_threshold = q1 - (interquartile_range * quartile_range_factor)
188
+ high_outlier_threshold = q3 + (interquartile_range * quartile_range_factor)
189
+ # puts("Outlier Thresholds = [#{low_outlier_threshold} <=> #{high_outlier_threshold}]")
190
+
191
+ return [low_outlier_threshold, high_outlier_threshold]
192
+ end
193
+
194
+ # Returns the average of the values in this array.
195
+ #
196
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
197
+ # This block can be safely skipped if the array contains numbers.
198
+ def average(&value_block) # :yields: element
199
+ s = sum(&value_block)
200
+ s = s.to_f if s.integer?
201
+ s / length
202
+ end
203
+
204
+ # Returns the sum of all the values in this array.
205
+ #
206
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
207
+ # This block can be safely skipped if the array contains numbers.
208
+ def sum(&value_block) # :yields: element
209
+ value_block = proc{|element| element} unless block_given?
210
+ s = 0
211
+ each do |element|
212
+ s = s + value_block.call(element)
213
+ end
214
+ s
215
+ end
216
+
217
+ @as_sort_dirty = true
218
+ @as_last_comparison_block = nil
219
+
220
+ alias old_sort! sort!
221
+ # Adds smarter sorting: A lot of methods above need the array sorted and they may call one another. This sort! method only sorts the
222
+ # array if it isn't currently known to be sorted.
223
+ #
224
+ # Like most methods in this package, this method takes an optional block that defines the "value" of the objects in the array.
225
+ # This block can be safely skipped if the array contains numbers.
226
+ def sort!(&comparison_block) # :yields: element
227
+ if(dirty? || (comparison_block != @as_last_comparison_block))
228
+ old_sort!(&comparison_block)
229
+ @as_last_comparison_block = comparison_block
230
+ clean
231
+ end
232
+ self
233
+ end
234
+
235
+ #:stopdoc:
236
+ def dirty
237
+ @as_sort_dirty = true
238
+ end
239
+
240
+ def dirty?
241
+ dirty unless instance_variable_defined? :@as_sort_dirty
242
+ @as_sort_dirty
243
+ end
244
+
245
+ def clean
246
+ @as_sort_dirty = false
247
+ end
248
+
249
+ # BELOW: Modify the array to mark itself as dirty when the array might need resorting.
250
+
251
+ # For our purposes "Dirty" doesn't merely mean that the array has been modified, It means
252
+ # that the array has been modified in a way that could have messed up the sorting.
253
+ # For this reason, not all methods that could modify the array are included. e.g. anything
254
+ # that *JUST* removes elements doesn't mess up the order of the array, but insertions might.
255
+
256
+ # Side-note: there are a lot of array methods that don't follow the destructive-methods-end-in-! naming pattern
257
+
258
+ alias as_old_ass []=
259
+ def []=(*as_args)
260
+ ret = as_old_ass(*as_args)
261
+ dirty
262
+ ret
263
+ end
264
+
265
+ alias as_old_app <<
266
+ def <<(*as_args)
267
+ ret = as_old_app(*as_args)
268
+ dirty
269
+ ret
270
+ end
271
+
272
+ alias as_old_push push
273
+ def push(*as_args)
274
+ ret = as_old_push(*as_args)
275
+ dirty
276
+ ret
277
+ end
278
+
279
+ alias as_old_collect collect!
280
+ def collect!(*as_args, &block)
281
+ ret = as_old_collect(*as_args, &block)
282
+ dirty
283
+ ret
284
+ end
285
+
286
+ alias as_old_map! map!
287
+ def map!(*as_args, &block)
288
+ ret = as_old_map!(*as_args, &block)
289
+ dirty
290
+ ret
291
+ end
292
+
293
+ alias as_old_fill fill
294
+ def fill(*as_args, &block)
295
+ ret = as_old_fill(*as_args, &block)
296
+ dirty
297
+ ret
298
+ end
299
+
300
+ alias as_old_flatten flatten!
301
+ def flatten!(*as_args, &block)
302
+ ret = as_old_flatten(*as_args, &block)
303
+ dirty
304
+ ret
305
+ end
306
+
307
+ alias as_old_replace replace
308
+ def replace(*as_args, &block)
309
+ ret = as_old_replace(*as_args, &block)
310
+ dirty
311
+ ret
312
+ end
313
+
314
+ alias as_old_reverse reverse!
315
+ def reverse!(*as_args, &block)
316
+ ret = as_old_reverse(*as_args, &block)
317
+ dirty
318
+ ret
319
+ end
320
+
321
+ alias as_old_unshift unshift
322
+ def unshift(*as_args, &block)
323
+ ret = as_old_unshift(*as_args, &block)
324
+ dirty
325
+ ret
326
+ end
327
+ #:startdoc:
328
+ end
329
+
330
+
331
+
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/array_statistics.rb'}"
9
+ puts "Loading array_statistics gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ load File.dirname(__FILE__) + "/../Rakefile"
4
+ require 'rubyforge'
5
+ require 'redcloth'
6
+ require 'syntax/convertors/html'
7
+ require 'erb'
8
+
9
+ download = "http://rubyforge.org/projects/#{$hoe.rubyforge_name}"
10
+ version = $hoe.version
11
+
12
+ def rubyforge_project_id
13
+ RubyForge.new.configure.autoconfig["group_ids"][$hoe.rubyforge_name]
14
+ end
15
+
16
+ class Fixnum
17
+ def ordinal
18
+ # teens
19
+ return 'th' if (10..19).include?(self % 100)
20
+ # others
21
+ case self % 10
22
+ when 1: return 'st'
23
+ when 2: return 'nd'
24
+ when 3: return 'rd'
25
+ else return 'th'
26
+ end
27
+ end
28
+ end
29
+
30
+ class Time
31
+ def pretty
32
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
33
+ end
34
+ end
35
+
36
+ def convert_syntax(syntax, source)
37
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
38
+ end
39
+
40
+ if ARGV.length >= 1
41
+ src, template = ARGV
42
+ template ||= File.join(File.dirname(__FILE__), '/../website/template.html.erb')
43
+ else
44
+ puts("Usage: #{File.split($0).last} source.txt [template.html.erb] > output.html")
45
+ exit!
46
+ end
47
+
48
+ template = ERB.new(File.open(template).read)
49
+
50
+ title = nil
51
+ body = nil
52
+ File.open(src) do |fsrc|
53
+ title_text = fsrc.readline
54
+ body_text_template = fsrc.read
55
+ body_text = ERB.new(body_text_template).result(binding)
56
+ syntax_items = []
57
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
58
+ ident = syntax_items.length
59
+ element, syntax, source = $1, $2, $3
60
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
61
+ "syntax-temp-#{ident}"
62
+ }
63
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
64
+ body = RedCloth.new(body_text).to_html
65
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
66
+ end
67
+ stat = File.stat(src)
68
+ created = stat.ctime
69
+ modified = stat.mtime
70
+
71
+ $stdout << template.result(binding)
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestArrayStatistics < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_empty_array
9
+ assert_same(0, [].median)
10
+ assert_same(0, [].median_indices)
11
+ end
12
+
13
+ def test_percentile
14
+ assert_nil([].percentile(1))
15
+ #edge cases
16
+ assert_nil([1,2,3,4,5,6,8].percentile(0))
17
+ assert_equal(8, [1,2,3,4,5,6,8].percentile(1))
18
+ assert_equal([1,2,3,4,5,6,8].percentile(135484), [1,2,3,4,5,6,8].percentile(1))
19
+ assert_equal([1,2,3,4,5,6,8].percentile(-3), [1,2,3,4,5,6,8].percentile(0))
20
+ #proper handling of midrange values
21
+ assert_equal(1, [1,2,3,4].percentile(0.0001))
22
+ assert_equal(1, [1,2,3,4].percentile(0.25))
23
+ assert_equal(1, [1,2,3,4].percentile(0.26))
24
+ assert_equal(2, [1,2,3,4].percentile(0.5))
25
+ end
26
+
27
+ def test_percentile_rank
28
+ #edge cases
29
+ assert_equal(0, [1,2,3,4].percentile_rank(-1))
30
+ assert_equal(1, [1,2,3,4].percentile_rank(19849))
31
+ #proper handling of midrange values
32
+ assert_equal(0, [1,2,3,4].percentile_rank(0.99))
33
+ assert_equal(0.25, [1,2,3,4].percentile_rank(1))
34
+ assert_equal(0.25, [1,2,3,4].percentile_rank(1.3))
35
+ end
36
+
37
+ def test_median
38
+ assert_equal(0, [].median)
39
+ assert_equal(666, [666].median)
40
+ assert_equal(1.5, [1,2].median)
41
+ assert_equal(3, [2,3,4].median)
42
+ assert_equal(2.5, [1,2,3,4].median)
43
+ end
44
+
45
+ def test_outliers
46
+ assert_equal([-60,999,9999], [-60,1,2,3,1,2,3,4,3,2,1,1,1,1,4,4,4,4,3,999, 9999].outliers)
47
+
48
+ end
49
+ end
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/array_statistics'
@@ -0,0 +1,11 @@
1
+ <html>
2
+ <head>
3
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
4
+ <title>array_statistics</title>
5
+
6
+ </head>
7
+ <body id="body">
8
+ <p>This page has not yet been created for RubyGem <code>array_statistics</code></p>
9
+ <p>To the developer: To generate it, update website/index.txt and run the rake task <code>website</code> to generate this <code>index.html</code> file.</p>
10
+ </body>
11
+ </html>
@@ -0,0 +1,83 @@
1
+ h1. array_statistics
2
+
3
+ h1. &#x2192; 'array_statistics'
4
+
5
+
6
+ h2. What
7
+
8
+
9
+ h2. Installing
10
+
11
+ <pre syntax="ruby">sudo gem install array_statistics</pre>
12
+
13
+ h2. The basics
14
+
15
+
16
+ h2. Demonstration of usage
17
+
18
+
19
+
20
+ h2. Forum
21
+
22
+ "http://groups.google.com/group/array_statistics":http://groups.google.com/group/array_statistics
23
+
24
+ TODO - create Google Group - array_statistics
25
+
26
+ h2. How to submit patches
27
+
28
+ Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/ and for section "8b: Submit patch to Google Groups":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups, use the Google Group above.
29
+
30
+ TODO - pick SVN or Git instructions
31
+
32
+ The trunk repository is <code>svn://rubyforge.org/var/svn/array_statistics/trunk</code> for anonymous access.
33
+
34
+ OOOORRRR
35
+
36
+ You can fetch the source from either:
37
+
38
+ <% if rubyforge_project_id %>
39
+
40
+ * rubyforge: "http://rubyforge.org/scm/?group_id=<%= rubyforge_project_id %>":http://rubyforge.org/scm/?group_id=<%= rubyforge_project_id %>
41
+
42
+ <pre>git clone git://rubyforge.org/array_statistics.git</pre>
43
+
44
+ <% else %>
45
+
46
+ * rubyforge: MISSING IN ACTION
47
+
48
+ TODO - You can not created a RubyForge project, OR have not run <code>rubyforge config</code>
49
+ yet to refresh your local rubyforge data with this projects' id information.
50
+
51
+ When you do this, this message will magically disappear!
52
+
53
+ Or you can hack website/index.txt and make it all go away!!
54
+
55
+ <% end %>
56
+
57
+ * github: "http://github.com/GITHUB_USERNAME/array_statistics/tree/master":http://github.com/GITHUB_USERNAME/array_statistics/tree/master
58
+
59
+ <pre>git clone git://github.com/GITHUB_USERNAME/array_statistics.git</pre>
60
+
61
+
62
+ TODO - add "github_username: username" to ~/.rubyforge/user-config.yml and newgem will reuse it for future projects.
63
+
64
+
65
+ * gitorious: "git://gitorious.org/array_statistics/mainline.git":git://gitorious.org/array_statistics/mainline.git
66
+
67
+ <pre>git clone git://gitorious.org/array_statistics/mainline.git</pre>
68
+
69
+ h3. Build and test instructions
70
+
71
+ <pre>cd array_statistics
72
+ rake test
73
+ rake install_gem</pre>
74
+
75
+
76
+ h2. License
77
+
78
+ This code is free to use under the terms of the MIT license.
79
+
80
+ h2. Contact
81
+
82
+ Comments are welcome. Send an email to "FIXME full name":mailto:FIXME email via the "forum":http://groups.google.com/group/array_statistics
83
+
@@ -0,0 +1,285 @@
1
+
2
+ /****************************************************************
3
+ * *
4
+ * curvyCorners *
5
+ * ------------ *
6
+ * *
7
+ * This script generates rounded corners for your divs. *
8
+ * *
9
+ * Version 1.2.9 *
10
+ * Copyright (c) 2006 Cameron Cooke *
11
+ * By: Cameron Cooke and Tim Hutchison. *
12
+ * *
13
+ * *
14
+ * Website: http://www.curvycorners.net *
15
+ * Email: info@totalinfinity.com *
16
+ * Forum: http://www.curvycorners.net/forum/ *
17
+ * *
18
+ * *
19
+ * This library is free software; you can redistribute *
20
+ * it and/or modify it under the terms of the GNU *
21
+ * Lesser General Public License as published by the *
22
+ * Free Software Foundation; either version 2.1 of the *
23
+ * License, or (at your option) any later version. *
24
+ * *
25
+ * This library is distributed in the hope that it will *
26
+ * be useful, but WITHOUT ANY WARRANTY; without even the *
27
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A *
28
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public *
29
+ * License for more details. *
30
+ * *
31
+ * You should have received a copy of the GNU Lesser *
32
+ * General Public License along with this library; *
33
+ * Inc., 59 Temple Place, Suite 330, Boston, *
34
+ * MA 02111-1307 USA *
35
+ * *
36
+ ****************************************************************/
37
+
38
+ var isIE = navigator.userAgent.toLowerCase().indexOf("msie") > -1; var isMoz = document.implementation && document.implementation.createDocument; var isSafari = ((navigator.userAgent.toLowerCase().indexOf('safari')!=-1)&&(navigator.userAgent.toLowerCase().indexOf('mac')!=-1))?true:false; function curvyCorners()
39
+ { if(typeof(arguments[0]) != "object") throw newCurvyError("First parameter of curvyCorners() must be an object."); if(typeof(arguments[1]) != "object" && typeof(arguments[1]) != "string") throw newCurvyError("Second parameter of curvyCorners() must be an object or a class name."); if(typeof(arguments[1]) == "string")
40
+ { var startIndex = 0; var boxCol = getElementsByClass(arguments[1]);}
41
+ else
42
+ { var startIndex = 1; var boxCol = arguments;}
43
+ var curvyCornersCol = new Array(); if(arguments[0].validTags)
44
+ var validElements = arguments[0].validTags; else
45
+ var validElements = ["div"]; for(var i = startIndex, j = boxCol.length; i < j; i++)
46
+ { var currentTag = boxCol[i].tagName.toLowerCase(); if(inArray(validElements, currentTag) !== false)
47
+ { curvyCornersCol[curvyCornersCol.length] = new curvyObject(arguments[0], boxCol[i]);}
48
+ }
49
+ this.objects = curvyCornersCol; this.applyCornersToAll = function()
50
+ { for(var x = 0, k = this.objects.length; x < k; x++)
51
+ { this.objects[x].applyCorners();}
52
+ }
53
+ }
54
+ function curvyObject()
55
+ { this.box = arguments[1]; this.settings = arguments[0]; this.topContainer = null; this.bottomContainer = null; this.masterCorners = new Array(); this.contentDIV = null; var boxHeight = get_style(this.box, "height", "height"); var boxWidth = get_style(this.box, "width", "width"); var borderWidth = get_style(this.box, "borderTopWidth", "border-top-width"); var borderColour = get_style(this.box, "borderTopColor", "border-top-color"); var boxColour = get_style(this.box, "backgroundColor", "background-color"); var backgroundImage = get_style(this.box, "backgroundImage", "background-image"); var boxPosition = get_style(this.box, "position", "position"); var boxPadding = get_style(this.box, "paddingTop", "padding-top"); this.boxHeight = parseInt(((boxHeight != "" && boxHeight != "auto" && boxHeight.indexOf("%") == -1)? boxHeight.substring(0, boxHeight.indexOf("px")) : this.box.scrollHeight)); this.boxWidth = parseInt(((boxWidth != "" && boxWidth != "auto" && boxWidth.indexOf("%") == -1)? boxWidth.substring(0, boxWidth.indexOf("px")) : this.box.scrollWidth)); this.borderWidth = parseInt(((borderWidth != "" && borderWidth.indexOf("px") !== -1)? borderWidth.slice(0, borderWidth.indexOf("px")) : 0)); this.boxColour = format_colour(boxColour); this.boxPadding = parseInt(((boxPadding != "" && boxPadding.indexOf("px") !== -1)? boxPadding.slice(0, boxPadding.indexOf("px")) : 0)); this.borderColour = format_colour(borderColour); this.borderString = this.borderWidth + "px" + " solid " + this.borderColour; this.backgroundImage = ((backgroundImage != "none")? backgroundImage : ""); this.boxContent = this.box.innerHTML; if(boxPosition != "absolute") this.box.style.position = "relative"; this.box.style.padding = "0px"; if(isIE && boxWidth == "auto" && boxHeight == "auto") this.box.style.width = "100%"; if(this.settings.autoPad == true && this.boxPadding > 0)
56
+ this.box.innerHTML = ""; this.applyCorners = function()
57
+ { for(var t = 0; t < 2; t++)
58
+ { switch(t)
59
+ { case 0:
60
+ if(this.settings.tl || this.settings.tr)
61
+ { var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var topMaxRadius = Math.max(this.settings.tl ? this.settings.tl.radius : 0, this.settings.tr ? this.settings.tr.radius : 0); newMainContainer.style.height = topMaxRadius + "px"; newMainContainer.style.top = 0 - topMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.topContainer = this.box.appendChild(newMainContainer);}
62
+ break; case 1:
63
+ if(this.settings.bl || this.settings.br)
64
+ { var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var botMaxRadius = Math.max(this.settings.bl ? this.settings.bl.radius : 0, this.settings.br ? this.settings.br.radius : 0); newMainContainer.style.height = botMaxRadius + "px"; newMainContainer.style.bottom = 0 - botMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.bottomContainer = this.box.appendChild(newMainContainer);}
65
+ break;}
66
+ }
67
+ if(this.topContainer) this.box.style.borderTopWidth = "0px"; if(this.bottomContainer) this.box.style.borderBottomWidth = "0px"; var corners = ["tr", "tl", "br", "bl"]; for(var i in corners)
68
+ { if(i > -1 < 4)
69
+ { var cc = corners[i]; if(!this.settings[cc])
70
+ { if(((cc == "tr" || cc == "tl") && this.topContainer != null) || ((cc == "br" || cc == "bl") && this.bottomContainer != null))
71
+ { var newCorner = document.createElement("DIV"); newCorner.style.position = "relative"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; if(this.backgroundImage == "")
72
+ newCorner.style.backgroundColor = this.boxColour; else
73
+ newCorner.style.backgroundImage = this.backgroundImage; switch(cc)
74
+ { case "tl":
75
+ newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.tr.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.left = -this.borderWidth + "px"; break; case "tr":
76
+ newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.tl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; newCorner.style.left = this.borderWidth + "px"; break; case "bl":
77
+ newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.br.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = -this.borderWidth + "px"; newCorner.style.backgroundPosition = "-" + (this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break; case "br":
78
+ newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.bl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = this.borderWidth + "px"
79
+ newCorner.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break;}
80
+ }
81
+ }
82
+ else
83
+ { if(this.masterCorners[this.settings[cc].radius])
84
+ { var newCorner = this.masterCorners[this.settings[cc].radius].cloneNode(true);}
85
+ else
86
+ { var newCorner = document.createElement("DIV"); newCorner.style.height = this.settings[cc].radius + "px"; newCorner.style.width = this.settings[cc].radius + "px"; newCorner.style.position = "absolute"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; var borderRadius = parseInt(this.settings[cc].radius - this.borderWidth); for(var intx = 0, j = this.settings[cc].radius; intx < j; intx++)
87
+ { if((intx +1) >= borderRadius)
88
+ var y1 = -1; else
89
+ var y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1); if(borderRadius != j)
90
+ { if((intx) >= borderRadius)
91
+ var y2 = -1; else
92
+ var y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2))); if((intx+1) >= j)
93
+ var y3 = -1; else
94
+ var y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);}
95
+ if((intx) >= j)
96
+ var y4 = -1; else
97
+ var y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2))); if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner, -1, this.settings[cc].radius); if(borderRadius != j)
98
+ { for(var inty = (y1 + 1); inty < y2; inty++)
99
+ { if(this.settings.antiAlias)
100
+ { if(this.backgroundImage != "")
101
+ { var borderFract = (pixelFraction(intx, inty, borderRadius) * 100); if(borderFract < 30)
102
+ { this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, 0, this.settings[cc].radius);}
103
+ else
104
+ { this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, -1, this.settings[cc].radius);}
105
+ }
106
+ else
107
+ { var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, borderRadius)); this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner, 0, this.settings[cc].radius, cc);}
108
+ }
109
+ }
110
+ if(this.settings.antiAlias)
111
+ { if(y3 >= y2)
112
+ { if (y2 == -1) y2 = 0; this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner, 0, 0);}
113
+ }
114
+ else
115
+ { if(y3 >= y1)
116
+ { this.drawPixel(intx, (y1 + 1), this.borderColour, 100, (y3 - y1), newCorner, 0, 0);}
117
+ }
118
+ var outsideColour = this.borderColour;}
119
+ else
120
+ { var outsideColour = this.boxColour; var y3 = y1;}
121
+ if(this.settings.antiAlias)
122
+ { for(var inty = (y3 + 1); inty < y4; inty++)
123
+ { this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty , j) * 100), 1, newCorner, ((this.borderWidth > 0)? 0 : -1), this.settings[cc].radius);}
124
+ }
125
+ }
126
+ this.masterCorners[this.settings[cc].radius] = newCorner.cloneNode(true);}
127
+ if(cc != "br")
128
+ { for(var t = 0, k = newCorner.childNodes.length; t < k; t++)
129
+ { var pixelBar = newCorner.childNodes[t]; var pixelBarTop = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px"))); var pixelBarLeft = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px"))); var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px"))); if(cc == "tl" || cc == "bl"){ pixelBar.style.left = this.settings[cc].radius -pixelBarLeft -1 + "px";}
130
+ if(cc == "tr" || cc == "tl"){ pixelBar.style.top = this.settings[cc].radius -pixelBarHeight -pixelBarTop + "px";}
131
+ switch(cc)
132
+ { case "tr":
133
+ pixelBar.style.backgroundPosition = "-" + Math.abs((this.boxWidth - this.settings[cc].radius + this.borderWidth) + pixelBarLeft) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "tl":
134
+ pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "bl":
135
+ pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs((this.boxHeight + this.settings[cc].radius + pixelBarTop) -this.borderWidth) + "px"; break;}
136
+ }
137
+ }
138
+ }
139
+ if(newCorner)
140
+ { switch(cc)
141
+ { case "tl":
142
+ if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "tr":
143
+ if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "bl":
144
+ if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break; case "br":
145
+ if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break;}
146
+ }
147
+ }
148
+ }
149
+ var radiusDiff = new Array(); radiusDiff["t"] = Math.abs(this.settings.tl.radius - this.settings.tr.radius)
150
+ radiusDiff["b"] = Math.abs(this.settings.bl.radius - this.settings.br.radius); for(z in radiusDiff)
151
+ { if(z == "t" || z == "b")
152
+ { if(radiusDiff[z])
153
+ { var smallerCornerType = ((this.settings[z + "l"].radius < this.settings[z + "r"].radius)? z +"l" : z +"r"); var newFiller = document.createElement("DIV"); newFiller.style.height = radiusDiff[z] + "px"; newFiller.style.width = this.settings[smallerCornerType].radius+ "px"
154
+ newFiller.style.position = "absolute"; newFiller.style.fontSize = "1px"; newFiller.style.overflow = "hidden"; newFiller.style.backgroundColor = this.boxColour; switch(smallerCornerType)
155
+ { case "tl":
156
+ newFiller.style.bottom = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.topContainer.appendChild(newFiller); break; case "tr":
157
+ newFiller.style.bottom = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.topContainer.appendChild(newFiller); break; case "bl":
158
+ newFiller.style.top = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.bottomContainer.appendChild(newFiller); break; case "br":
159
+ newFiller.style.top = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.bottomContainer.appendChild(newFiller); break;}
160
+ }
161
+ var newFillerBar = document.createElement("DIV"); newFillerBar.style.position = "relative"; newFillerBar.style.fontSize = "1px"; newFillerBar.style.overflow = "hidden"; newFillerBar.style.backgroundColor = this.boxColour; newFillerBar.style.backgroundImage = this.backgroundImage; switch(z)
162
+ { case "t":
163
+ if(this.topContainer)
164
+ { if(this.settings.tl.radius && this.settings.tr.radius)
165
+ { newFillerBar.style.height = topMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.tl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.tr.radius - this.borderWidth + "px"; newFillerBar.style.borderTop = this.borderString; if(this.backgroundImage != "")
166
+ newFillerBar.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; this.topContainer.appendChild(newFillerBar);}
167
+ this.box.style.backgroundPosition = "0px -" + (topMaxRadius - this.borderWidth) + "px";}
168
+ break; case "b":
169
+ if(this.bottomContainer)
170
+ { if(this.settings.bl.radius && this.settings.br.radius)
171
+ { newFillerBar.style.height = botMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.bl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.br.radius - this.borderWidth + "px"; newFillerBar.style.borderBottom = this.borderString; if(this.backgroundImage != "")
172
+ newFillerBar.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (topMaxRadius + this.borderWidth)) + "px"; this.bottomContainer.appendChild(newFillerBar);}
173
+ }
174
+ break;}
175
+ }
176
+ }
177
+ if(this.settings.autoPad == true && this.boxPadding > 0)
178
+ { var contentContainer = document.createElement("DIV"); contentContainer.style.position = "relative"; contentContainer.innerHTML = this.boxContent; contentContainer.className = "autoPadDiv"; var topPadding = Math.abs(topMaxRadius - this.boxPadding); var botPadding = Math.abs(botMaxRadius - this.boxPadding); if(topMaxRadius < this.boxPadding)
179
+ contentContainer.style.paddingTop = topPadding + "px"; if(botMaxRadius < this.boxPadding)
180
+ contentContainer.style.paddingBottom = botMaxRadius + "px"; contentContainer.style.paddingLeft = this.boxPadding + "px"; contentContainer.style.paddingRight = this.boxPadding + "px"; this.contentDIV = this.box.appendChild(contentContainer);}
181
+ }
182
+ this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius)
183
+ { var pixel = document.createElement("DIV"); pixel.style.height = height + "px"; pixel.style.width = "1px"; pixel.style.position = "absolute"; pixel.style.fontSize = "1px"; pixel.style.overflow = "hidden"; var topMaxRadius = Math.max(this.settings["tr"].radius, this.settings["tl"].radius); if(image == -1 && this.backgroundImage != "")
184
+ { pixel.style.backgroundImage = this.backgroundImage; pixel.style.backgroundPosition = "-" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + "px -" + ((this.boxHeight + topMaxRadius + inty) -this.borderWidth) + "px";}
185
+ else
186
+ { pixel.style.backgroundColor = colour;}
187
+ if (transAmount != 100)
188
+ setOpacity(pixel, transAmount); pixel.style.top = inty + "px"; pixel.style.left = intx + "px"; newCorner.appendChild(pixel);}
189
+ }
190
+ function insertAfter(parent, node, referenceNode)
191
+ { parent.insertBefore(node, referenceNode.nextSibling);}
192
+ function BlendColour(Col1, Col2, Col1Fraction)
193
+ { var red1 = parseInt(Col1.substr(1,2),16); var green1 = parseInt(Col1.substr(3,2),16); var blue1 = parseInt(Col1.substr(5,2),16); var red2 = parseInt(Col2.substr(1,2),16); var green2 = parseInt(Col2.substr(3,2),16); var blue2 = parseInt(Col2.substr(5,2),16); if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1; var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction))); if(endRed > 255) endRed = 255; if(endRed < 0) endRed = 0; var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction))); if(endGreen > 255) endGreen = 255; if(endGreen < 0) endGreen = 0; var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction))); if(endBlue > 255) endBlue = 255; if(endBlue < 0) endBlue = 0; return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);}
194
+ function IntToHex(strNum)
195
+ { base = strNum / 16; rem = strNum % 16; base = base - (rem / 16); baseS = MakeHex(base); remS = MakeHex(rem); return baseS + '' + remS;}
196
+ function MakeHex(x)
197
+ { if((x >= 0) && (x <= 9))
198
+ { return x;}
199
+ else
200
+ { switch(x)
201
+ { case 10: return "A"; case 11: return "B"; case 12: return "C"; case 13: return "D"; case 14: return "E"; case 15: return "F";}
202
+ }
203
+ }
204
+ function pixelFraction(x, y, r)
205
+ { var pixelfraction = 0; var xvalues = new Array(1); var yvalues = new Array(1); var point = 0; var whatsides = ""; var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2))); if ((intersect >= y) && (intersect < (y+1)))
206
+ { whatsides = "Left"; xvalues[point] = 0; yvalues[point] = intersect - y; point = point + 1;}
207
+ var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2))); if ((intersect >= x) && (intersect < (x+1)))
208
+ { whatsides = whatsides + "Top"; xvalues[point] = intersect - x; yvalues[point] = 1; point = point + 1;}
209
+ var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2))); if ((intersect >= y) && (intersect < (y+1)))
210
+ { whatsides = whatsides + "Right"; xvalues[point] = 1; yvalues[point] = intersect - y; point = point + 1;}
211
+ var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2))); if ((intersect >= x) && (intersect < (x+1)))
212
+ { whatsides = whatsides + "Bottom"; xvalues[point] = intersect - x; yvalues[point] = 0;}
213
+ switch (whatsides)
214
+ { case "LeftRight":
215
+ pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2); break; case "TopRight":
216
+ pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2); break; case "TopBottom":
217
+ pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2); break; case "LeftBottom":
218
+ pixelfraction = (yvalues[0]*xvalues[1])/2; break; default:
219
+ pixelfraction = 1;}
220
+ return pixelfraction;}
221
+ function rgb2Hex(rgbColour)
222
+ { try{ var rgbArray = rgb2Array(rgbColour); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue);}
223
+ catch(e){ alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");}
224
+ return hexColour;}
225
+ function rgb2Array(rgbColour)
226
+ { var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")")); var rgbArray = rgbValues.split(", "); return rgbArray;}
227
+ function setOpacity(obj, opacity)
228
+ { opacity = (opacity == 100)?99.999:opacity; if(isSafari && obj.tagName != "IFRAME")
229
+ { var rgbArray = rgb2Array(obj.style.backgroundColor); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); obj.style.backgroundColor = "rgba(" + red + ", " + green + ", " + blue + ", " + opacity/100 + ")";}
230
+ else if(typeof(obj.style.opacity) != "undefined")
231
+ { obj.style.opacity = opacity/100;}
232
+ else if(typeof(obj.style.MozOpacity) != "undefined")
233
+ { obj.style.MozOpacity = opacity/100;}
234
+ else if(typeof(obj.style.filter) != "undefined")
235
+ { obj.style.filter = "alpha(opacity:" + opacity + ")";}
236
+ else if(typeof(obj.style.KHTMLOpacity) != "undefined")
237
+ { obj.style.KHTMLOpacity = opacity/100;}
238
+ }
239
+ function inArray(array, value)
240
+ { for(var i = 0; i < array.length; i++){ if (array[i] === value) return i;}
241
+ return false;}
242
+ function inArrayKey(array, value)
243
+ { for(key in array){ if(key === value) return true;}
244
+ return false;}
245
+ function addEvent(elm, evType, fn, useCapture) { if (elm.addEventListener) { elm.addEventListener(evType, fn, useCapture); return true;}
246
+ else if (elm.attachEvent) { var r = elm.attachEvent('on' + evType, fn); return r;}
247
+ else { elm['on' + evType] = fn;}
248
+ }
249
+ function removeEvent(obj, evType, fn, useCapture){ if (obj.removeEventListener){ obj.removeEventListener(evType, fn, useCapture); return true;} else if (obj.detachEvent){ var r = obj.detachEvent("on"+evType, fn); return r;} else { alert("Handler could not be removed");}
250
+ }
251
+ function format_colour(colour)
252
+ { var returnColour = "#ffffff"; if(colour != "" && colour != "transparent")
253
+ { if(colour.substr(0, 3) == "rgb")
254
+ { returnColour = rgb2Hex(colour);}
255
+ else if(colour.length == 4)
256
+ { returnColour = "#" + colour.substring(1, 2) + colour.substring(1, 2) + colour.substring(2, 3) + colour.substring(2, 3) + colour.substring(3, 4) + colour.substring(3, 4);}
257
+ else
258
+ { returnColour = colour;}
259
+ }
260
+ return returnColour;}
261
+ function get_style(obj, property, propertyNS)
262
+ { try
263
+ { if(obj.currentStyle)
264
+ { var returnVal = eval("obj.currentStyle." + property);}
265
+ else
266
+ { if(isSafari && obj.style.display == "none")
267
+ { obj.style.display = ""; var wasHidden = true;}
268
+ var returnVal = document.defaultView.getComputedStyle(obj, '').getPropertyValue(propertyNS); if(isSafari && wasHidden)
269
+ { obj.style.display = "none";}
270
+ }
271
+ }
272
+ catch(e)
273
+ { }
274
+ return returnVal;}
275
+ function getElementsByClass(searchClass, node, tag)
276
+ { var classElements = new Array(); if(node == null)
277
+ node = document; if(tag == null)
278
+ tag = '*'; var els = node.getElementsByTagName(tag); var elsLen = els.length; var pattern = new RegExp("(^|\s)"+searchClass+"(\s|$)"); for (i = 0, j = 0; i < elsLen; i++)
279
+ { if(pattern.test(els[i].className))
280
+ { classElements[j] = els[i]; j++;}
281
+ }
282
+ return classElements;}
283
+ function newCurvyError(errorMessage)
284
+ { return new Error("curvyCorners Error:\n" + errorMessage)
285
+ }
@@ -0,0 +1,138 @@
1
+ body {
2
+ background-color: #E1D1F1;
3
+ font-family: "Georgia", sans-serif;
4
+ font-size: 16px;
5
+ line-height: 1.6em;
6
+ padding: 1.6em 0 0 0;
7
+ color: #333;
8
+ }
9
+ h1, h2, h3, h4, h5, h6 {
10
+ color: #444;
11
+ }
12
+ h1 {
13
+ font-family: sans-serif;
14
+ font-weight: normal;
15
+ font-size: 4em;
16
+ line-height: 0.8em;
17
+ letter-spacing: -0.1ex;
18
+ margin: 5px;
19
+ }
20
+ li {
21
+ padding: 0;
22
+ margin: 0;
23
+ list-style-type: square;
24
+ }
25
+ a {
26
+ color: #5E5AFF;
27
+ background-color: #DAC;
28
+ font-weight: normal;
29
+ text-decoration: underline;
30
+ }
31
+ blockquote {
32
+ font-size: 90%;
33
+ font-style: italic;
34
+ border-left: 1px solid #111;
35
+ padding-left: 1em;
36
+ }
37
+ .caps {
38
+ font-size: 80%;
39
+ }
40
+
41
+ #main {
42
+ width: 45em;
43
+ padding: 0;
44
+ margin: 0 auto;
45
+ }
46
+ .coda {
47
+ text-align: right;
48
+ color: #77f;
49
+ font-size: smaller;
50
+ }
51
+
52
+ table {
53
+ font-size: 90%;
54
+ line-height: 1.4em;
55
+ color: #ff8;
56
+ background-color: #111;
57
+ padding: 2px 10px 2px 10px;
58
+ border-style: dashed;
59
+ }
60
+
61
+ th {
62
+ color: #fff;
63
+ }
64
+
65
+ td {
66
+ padding: 2px 10px 2px 10px;
67
+ }
68
+
69
+ .success {
70
+ color: #0CC52B;
71
+ }
72
+
73
+ .failed {
74
+ color: #E90A1B;
75
+ }
76
+
77
+ .unknown {
78
+ color: #995000;
79
+ }
80
+ pre, code {
81
+ font-family: monospace;
82
+ font-size: 90%;
83
+ line-height: 1.4em;
84
+ color: #ff8;
85
+ background-color: #111;
86
+ padding: 2px 10px 2px 10px;
87
+ }
88
+ .comment { color: #aaa; font-style: italic; }
89
+ .keyword { color: #eff; font-weight: bold; }
90
+ .punct { color: #eee; font-weight: bold; }
91
+ .symbol { color: #0bb; }
92
+ .string { color: #6b4; }
93
+ .ident { color: #ff8; }
94
+ .constant { color: #66f; }
95
+ .regex { color: #ec6; }
96
+ .number { color: #F99; }
97
+ .expr { color: #227; }
98
+
99
+ #version {
100
+ float: right;
101
+ text-align: right;
102
+ font-family: sans-serif;
103
+ font-weight: normal;
104
+ background-color: #B3ABFF;
105
+ color: #141331;
106
+ padding: 15px 20px 10px 20px;
107
+ margin: 0 auto;
108
+ margin-top: 15px;
109
+ border: 3px solid #141331;
110
+ }
111
+
112
+ #version .numbers {
113
+ display: block;
114
+ font-size: 4em;
115
+ line-height: 0.8em;
116
+ letter-spacing: -0.1ex;
117
+ margin-bottom: 15px;
118
+ }
119
+
120
+ #version p {
121
+ text-decoration: none;
122
+ color: #141331;
123
+ background-color: #B3ABFF;
124
+ margin: 0;
125
+ padding: 0;
126
+ }
127
+
128
+ #version a {
129
+ text-decoration: none;
130
+ color: #141331;
131
+ background-color: #B3ABFF;
132
+ }
133
+
134
+ .clickable {
135
+ cursor: pointer;
136
+ cursor: hand;
137
+ }
138
+
@@ -0,0 +1,48 @@
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
+ <%= title %>
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><%= title %></h1>
34
+ <div id="version" class="clickable" onclick='document.location = "<%= download %>"; return false'>
35
+ <p>Get Version</p>
36
+ <a href="<%= download %>" class="numbers"><%= version %></a>
37
+ </div>
38
+ <%= body %>
39
+ <p class="coda">
40
+ <a href="FIXME email">FIXME full name</a>, <%= modified.pretty %><br>
41
+ Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
42
+ </p>
43
+ </div>
44
+
45
+ <!-- insert site tracking codes here, like Google Urchin -->
46
+
47
+ </body>
48
+ </html>
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: array_statistics
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Bruce Goodwin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-10-30 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: newgem
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.2
34
+ version:
35
+ description: Array Statistics adds statistical operations to the ruby Array class.
36
+ email:
37
+ - rubybg@gmail.com
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - PostInstall.txt
46
+ - website/index.txt
47
+ files:
48
+ - History.txt
49
+ - Manifest.txt
50
+ - PostInstall.txt
51
+ - README.rdoc
52
+ - Rakefile
53
+ - config/website.yml.sample
54
+ - lib/array_statistics.rb
55
+ - script/console
56
+ - script/destroy
57
+ - script/generate
58
+ - script/txt2html
59
+ - test/test_array_statistics.rb
60
+ - test/test_helper.rb
61
+ - website/index.html
62
+ - website/index.txt
63
+ - website/javascripts/rounded_corners_lite.inc.js
64
+ - website/stylesheets/screen.css
65
+ - website/template.html.erb
66
+ has_rdoc: true
67
+ homepage: http://rubyforge.org/projects/array-statistic/
68
+ post_install_message: PostInstall.txt
69
+ rdoc_options:
70
+ - --main
71
+ - README.rdoc
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ requirements: []
87
+
88
+ rubyforge_project: array_statistics
89
+ rubygems_version: 1.3.1
90
+ signing_key:
91
+ specification_version: 2
92
+ summary: Array Statistics adds statistical operations to the ruby Array class.
93
+ test_files:
94
+ - test/test_array_statistics.rb
95
+ - test/test_helper.rb