norikra-udf-percentile 0.0.1-java

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,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1 @@
1
+ jruby-1.7.4
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in norikra-udf-percentile.gemspec
4
+ gemspec
@@ -0,0 +1,29 @@
1
+ # Norikra::Udf::Percentile
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'norikra-udf-percentile'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install norikra-udf-percentile
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,27 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec) do |t|
5
+ t.rspec_opts = ["-c", "-f progress"] # '--format specdoc'
6
+ t.pattern = 'spec/**/*_spec.rb'
7
+ end
8
+
9
+ task :compile do
10
+ require 'rubygems'
11
+
12
+ jarname = FileList['norikra-udf-*.gemspec'].first.gsub(/\.gemspec$/, '.jar')
13
+
14
+ jarfiles = FileList['jar/**/*.jar'].select{|f| not f.end_with?('/' + jarname)}
15
+ jarfiles << Gem.find_files('esper-*.jar').first
16
+ classpath = "-classpath java:#{jarfiles.join(':')}"
17
+
18
+ FileList['java/**/*.java'].each do |fn|
19
+ sh "env LC_ALL=C javac #{classpath} #{fn}"
20
+ end
21
+ sh "env LC_ALL=C jar -cf jar/#{jarname} -C java ."
22
+ end
23
+
24
+ task :test => [:compile, :spec]
25
+ task :default => :test
26
+
27
+ task :all => [:compile, :spec, :build]
@@ -0,0 +1,88 @@
1
+ package is.tagomor.norikra.udf;
2
+
3
+ import com.espertech.esper.epl.agg.aggregator.AggregationMethod;
4
+
5
+ import java.util.ArrayList;
6
+ import java.util.Random;
7
+
8
+ public class Percentile implements AggregationMethod {
9
+ private static int initSize = 100000;
10
+
11
+ private ArrayList<Double> valueList;
12
+ private Integer target;
13
+
14
+ private Double last;
15
+
16
+ public Percentile() {
17
+ valueList = null;
18
+ last = null;
19
+ }
20
+
21
+ public long valueListSize() {
22
+ return valueList.size();
23
+ }
24
+
25
+ public Class getValueType() {
26
+ return Double.class;
27
+ }
28
+
29
+ public Double convertValue(Object v) {
30
+ if (v.getClass() == Double.class)
31
+ return (Double) v;
32
+ else if (v.getClass() == Float.class)
33
+ return new Double( ((Float) v).doubleValue() );
34
+ else if (v.getClass() == Integer.class)
35
+ return new Double( ((Integer) v).doubleValue() );
36
+ else if (v.getClass() == Long.class)
37
+ return new Double( ((Long) v).doubleValue() );
38
+ else
39
+ return new Double((String) v);
40
+ }
41
+
42
+ public void enter(Object value) {
43
+ if (value == null)
44
+ return;
45
+
46
+ Object[] objs = (Object[]) value;
47
+ if (valueList == null) {
48
+ target = (Integer) objs[1];
49
+ valueList = new ArrayList<Double>(initSize);
50
+ }
51
+
52
+ Double d = convertValue(objs[0]);
53
+ synchronized (valueList) {
54
+ valueList.add(d);
55
+ }
56
+ }
57
+
58
+ public void leave(Object value) {
59
+ if (value == null)
60
+ return;
61
+
62
+ Object[] objs = (Object[]) value;
63
+ Double d = convertValue(objs[0]);
64
+ synchronized (valueList) {
65
+ valueList.remove(d);
66
+ }
67
+ }
68
+
69
+ public Object getValue() {
70
+ if (valueList.size() == 0)
71
+ return last;
72
+
73
+ Double[] values = (Double[]) valueList.toArray(new Double[]{});
74
+
75
+ // for thread safety
76
+ if (values.length == 0)
77
+ return last;
78
+
79
+ java.util.Arrays.sort(values);
80
+ int size = values.length;
81
+ last = values[size * target / 100];
82
+ return last;
83
+ }
84
+
85
+ public void clear() {
86
+ valueList = null;
87
+ }
88
+ }
@@ -0,0 +1,53 @@
1
+ package is.tagomor.norikra.udf;
2
+
3
+ import com.espertech.esper.client.hook.AggregationFunctionFactory;
4
+ import com.espertech.esper.epl.agg.service.AggregationValidationContext;
5
+ import com.espertech.esper.epl.agg.aggregator.AggregationMethod;
6
+
7
+ // import java.util.Map;
8
+
9
+ public class PercentileFactory implements AggregationFunctionFactory {
10
+ public void setFunctionName(String functionName) {
11
+ // no action taken
12
+ }
13
+
14
+ /*
15
+ percentile(field_name, {percentile_specifications_array}[, samples])
16
+ ex: percentile(response_time, 50)
17
+ */
18
+ public void validate(AggregationValidationContext validationContext) {
19
+ if (validationContext.getParameterTypes().length != 2)
20
+ throw new IllegalArgumentException("percentile() accepts 2 arguments (fieldname,percentiles)");
21
+
22
+ Class first = validationContext.getParameterTypes()[0];
23
+ if (! (first == int.class || first == long.class || first == double.class || first == float.class ||
24
+ first == Integer.class || first == Long.class || first == Double.class || first == Float.class ||
25
+ first == String.class))
26
+ throw new IllegalArgumentException("percentile() first argument must be string or number, but " + first.toString());
27
+
28
+ Class second = validationContext.getParameterTypes()[1];
29
+ boolean f_second = validationContext.getIsConstantValue()[1];
30
+ if ((second != Integer.class && second != int.class) || !f_second)
31
+ throw new IllegalArgumentException("percentile() second argument must be Constant Integer");
32
+
33
+ if (validationContext.isDistinct())
34
+ throw new IllegalArgumentException("percentile() doesn't permit DISTINCT modifier");
35
+ }
36
+
37
+ /*
38
+ In order for the engine to validate the type returned by the aggregation function against
39
+ the types expected by enclosing expressions, the getValueType must return the result type
40
+ of any values produced by the aggregation function:
41
+ */
42
+ public Class getValueType() {
43
+ return Double.class;
44
+ }
45
+
46
+ /*
47
+ Finally the factory implementation must provide a newAggregator method that returns instances
48
+ of AggregationMethod. The engine invokes this method for each new aggregation state to be allocated.
49
+ */
50
+ public AggregationMethod newAggregator() {
51
+ return new Percentile();
52
+ }
53
+ }
@@ -0,0 +1,94 @@
1
+ package is.tagomor.norikra.udf;
2
+
3
+ import com.espertech.esper.epl.agg.aggregator.AggregationMethod;
4
+
5
+ import java.util.ArrayList;
6
+ import java.util.Random;
7
+
8
+ public class Percentiles implements AggregationMethod {
9
+ private static int initSize = 100000;
10
+
11
+ private ArrayList<Double> valueList;
12
+ private Integer[] targets;
13
+
14
+ private Double[] last;
15
+
16
+ public Percentiles() {
17
+ valueList = null;
18
+ last = null;
19
+ }
20
+
21
+ public long valueListSize() {
22
+ return valueList.size();
23
+ }
24
+
25
+ public Class getValueType() {
26
+ return Double[].class;
27
+ }
28
+
29
+ public Double convertValue(Object v) {
30
+ if (v.getClass() == Double.class)
31
+ return (Double) v;
32
+ else if (v.getClass() == Float.class)
33
+ return new Double( ((Float) v).doubleValue() );
34
+ else if (v.getClass() == Integer.class)
35
+ return new Double( ((Integer) v).doubleValue() );
36
+ else if (v.getClass() == Long.class)
37
+ return new Double( ((Long) v).doubleValue() );
38
+ else
39
+ return new Double((String) v);
40
+ }
41
+
42
+ public void enter(Object value) {
43
+ if (value == null)
44
+ return;
45
+
46
+ Object[] objs = (Object[]) value;
47
+ if (valueList == null) {
48
+ targets = (Integer[]) objs[1];
49
+ valueList = new ArrayList<Double>(initSize);
50
+ }
51
+
52
+ Double d = convertValue(objs[0]);
53
+ synchronized (valueList) {
54
+ valueList.add(d);
55
+ }
56
+ }
57
+
58
+ public void leave(Object value) {
59
+ if (value == null)
60
+ return;
61
+
62
+ Object[] objs = (Object[]) value;
63
+ Double d = convertValue(objs[0]);
64
+ synchronized (valueList) {
65
+ valueList.remove(d);
66
+ }
67
+ }
68
+
69
+ public Object getValue() {
70
+ if (valueList.size() == 0)
71
+ return last;
72
+
73
+ ArrayList<Double> percentiles = new ArrayList<Double>(targets.length);
74
+ Double[] values = (Double[]) valueList.toArray(new Double[]{});
75
+
76
+ // for thread safety
77
+ if (values.length == 0)
78
+ return last;
79
+
80
+ java.util.Arrays.sort(values);
81
+ int size = values.length;
82
+
83
+ for (int i = 0 ; i < targets.length ; i += 1) {
84
+ percentiles.add(values[size * targets[i] / 100]);
85
+ }
86
+
87
+ last = (Double[]) percentiles.toArray(new Double[]{});
88
+ return last;
89
+ }
90
+
91
+ public void clear() {
92
+ valueList = null;
93
+ }
94
+ }
@@ -0,0 +1,53 @@
1
+ package is.tagomor.norikra.udf;
2
+
3
+ import com.espertech.esper.client.hook.AggregationFunctionFactory;
4
+ import com.espertech.esper.epl.agg.service.AggregationValidationContext;
5
+ import com.espertech.esper.epl.agg.aggregator.AggregationMethod;
6
+
7
+ // import java.util.Map;
8
+
9
+ public class PercentilesFactory implements AggregationFunctionFactory {
10
+ public void setFunctionName(String functionName) {
11
+ // no action taken
12
+ }
13
+
14
+ /*
15
+ percentiles(field_name, {percentile_specifications_array}[, samples])
16
+ ex: percentiles(response_time, {50,90,95,98,99})
17
+ */
18
+ public void validate(AggregationValidationContext validationContext) {
19
+ if (validationContext.getParameterTypes().length != 2)
20
+ throw new IllegalArgumentException("percentiles() accepts 2 arguments (fieldname,percentiles)");
21
+
22
+ Class first = validationContext.getParameterTypes()[0];
23
+ if (! (first == int.class || first == long.class || first == double.class || first == float.class ||
24
+ first == Integer.class || first == Long.class || first == Double.class || first == Float.class ||
25
+ first == String.class))
26
+ throw new IllegalArgumentException("percentiles() first argument must be string or number, but " + first.toString());
27
+
28
+ Class second = validationContext.getParameterTypes()[1];
29
+ boolean f_second = validationContext.getIsConstantValue()[1];
30
+ if (second != Integer[].class || !f_second)
31
+ throw new IllegalArgumentException("percentiles() second argument must be Constant Array of Integer");
32
+
33
+ if (validationContext.isDistinct())
34
+ throw new IllegalArgumentException("percentiles() doesn't permit DISTINCT modifier");
35
+ }
36
+
37
+ /*
38
+ In order for the engine to validate the type returned by the aggregation function against
39
+ the types expected by enclosing expressions, the getValueType must return the result type
40
+ of any values produced by the aggregation function:
41
+ */
42
+ public Class getValueType() {
43
+ return Double[].class;
44
+ }
45
+
46
+ /*
47
+ Finally the factory implementation must provide a newAggregator method that returns instances
48
+ of AggregationMethod. The engine invokes this method for each new aggregation state to be allocated.
49
+ */
50
+ public AggregationMethod newAggregator() {
51
+ return new Percentiles();
52
+ }
53
+ }
@@ -0,0 +1,23 @@
1
+ require 'norikra/udf'
2
+
3
+ module Norikra
4
+ module UDF
5
+ class Percentile < Norikra::UDF::AggregationSingle
6
+ def self.init
7
+ require 'norikra-udf-percentile.jar'
8
+ end
9
+ def definition
10
+ ["percentile", "is.tagomor.norikra.udf.PercentileFactory"]
11
+ end
12
+ end
13
+
14
+ class Percentiles < Norikra::UDF::AggregationSingle
15
+ def self.init
16
+ require 'norikra-udf-percentile.jar'
17
+ end
18
+ def definition
19
+ ["percentiles", "is.tagomor.norikra.udf.PercentilesFactory"]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "norikra-udf-percentile"
5
+ spec.version = "0.0.1"
6
+ spec.authors = ["TAGOMORI Satoshi"]
7
+ spec.email = ["tagomoris@gmail.com"]
8
+ spec.description = %q{This plugin adds functions named percentile/percentiles, which calculate percentile for specified fields}
9
+ spec.summary = %q{Norikra UDF percentile() and percentiles()}
10
+ spec.homepage = "https://github.com/tagomoris/norikra-udf-percentile"
11
+ spec.license = "GPLv2"
12
+ spec.platform = "java"
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib", "jar"]
18
+
19
+ spec.add_runtime_dependency "norikra", ">= 0.0.9"
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,64 @@
1
+ require 'norikra/udf_spec_helper'
2
+
3
+ include Norikra::UDFSpecHelper
4
+
5
+ require 'norikra/udf/percentile'
6
+
7
+ describe Norikra::UDF::Percentile do
8
+ f = udf_function(
9
+ Norikra::UDF::Percentile,
10
+ :valueType => java.lang.Double,
11
+ :parameters => [
12
+ [java.lang.String, false],
13
+ [java.lang.Integer, true, 50],
14
+ ]
15
+ )
16
+
17
+ it 'returns Double values' do
18
+ expect(f.getValueType).to eql(java.lang.Double.java_class)
19
+ end
20
+
21
+ it 'returns 9 values as percentiles, and reflect for leve()' do
22
+ (0...100).each do |i|
23
+ f._call(:enter, [i.to_s, 50.to_java(:Integer)].to_java)
24
+ end
25
+
26
+ r = f.getValue
27
+ expect(r).to eql(50.0)
28
+
29
+ (0...50).each do |i|
30
+ f._call(:leave, [i.to_s, 50.to_java(:Integer)].to_java)
31
+ end
32
+
33
+ expect(f.instance_eval{ @func.valueListSize }).to eql(50)
34
+
35
+ r = f.getValue
36
+ expect(r).to eql(75.0)
37
+ end
38
+
39
+ f2 = udf_function(
40
+ Norikra::UDF::Percentile,
41
+ :valueType => java.lang.Double,
42
+ :parameters => [
43
+ [java.lang.Integer, false],
44
+ [java.lang.Integer, true, 90],
45
+ ]
46
+ )
47
+ it 'returns 5 values as percentiles, and returns same value after all values leaving' do
48
+ (0...2000).to_a.shuffle.each do |i|
49
+ f2._call(:enter, [i, 90.to_java(:Integer)].to_java)
50
+ end
51
+
52
+ expect(f2.instance_eval{ @func.valueListSize }).to eql(2000)
53
+
54
+ r = f2.getValue
55
+ expect(r).to eql(1800.0)
56
+
57
+ (0...2000).to_a.shuffle.each do |i|
58
+ f2._call(:leave, [i, 90.to_java(:Integer)].to_java)
59
+ end
60
+
61
+ r2 = f2.getValue
62
+ expect(r2).to eql(r)
63
+ end
64
+ end
@@ -0,0 +1,82 @@
1
+ require 'norikra/udf_spec_helper'
2
+
3
+ include Norikra::UDFSpecHelper
4
+
5
+ require 'norikra/udf/percentile'
6
+
7
+ describe Norikra::UDF::Percentiles do
8
+ f = udf_function(
9
+ Norikra::UDF::Percentiles,
10
+ :valueType => java.lang.Double[],
11
+ :parameters => [
12
+ [java.lang.String, false],
13
+ [java.lang.Integer[], true, [10,20,30,40,50,60,70,80,90].to_java(:Integer)].to_java,
14
+ ]
15
+ )
16
+
17
+ it 'returns Double[] values' do
18
+ expect(f.getValueType).to eql(java.lang.Double[].java_class)
19
+ end
20
+
21
+ it 'returns 9 values as percentiles, and reflect for leve()' do
22
+ (0...100).each do |i|
23
+ f._call(:enter, [i.to_s, [10,20,30,40,50,60,70,80,90].to_java(:Integer)].to_java)
24
+ end
25
+
26
+ r = f.getValue
27
+ expect(r.size).to eql(9)
28
+ expect(r[0]).to eql(10.0)
29
+ expect(r[1]).to eql(20.0)
30
+ expect(r[2]).to eql(30.0)
31
+ expect(r[3]).to eql(40.0)
32
+ expect(r[4]).to eql(50.0)
33
+ expect(r[5]).to eql(60.0)
34
+ expect(r[6]).to eql(70.0)
35
+ expect(r[7]).to eql(80.0)
36
+ expect(r[8]).to eql(90.0)
37
+
38
+ (0...50).each do |i|
39
+ f._call(:leave, [i.to_s, [10,20,30,40,50,60,70,80,90].to_java(:Integer)].to_java)
40
+ end
41
+
42
+ expect(f.instance_eval{ @func.valueListSize }).to eql(50)
43
+
44
+ r = f.getValue
45
+ expect(r.size).to eql(9)
46
+ expect(r[0]).to eql(55.0)
47
+ expect(r[1]).to eql(60.0)
48
+ expect(r[2]).to eql(65.0)
49
+ expect(r[3]).to eql(70.0)
50
+ expect(r[4]).to eql(75.0)
51
+ expect(r[5]).to eql(80.0)
52
+ expect(r[6]).to eql(85.0)
53
+ expect(r[7]).to eql(90.0)
54
+ expect(r[8]).to eql(95.0)
55
+ end
56
+
57
+ f2 = udf_function(
58
+ Norikra::UDF::Percentiles,
59
+ :valueType => java.lang.Double[],
60
+ :parameters => [
61
+ [java.lang.Integer, false],
62
+ [java.lang.Integer[], true, [50,90,95,98,99].to_java(:Integer)].to_java,
63
+ ]
64
+ )
65
+ it 'returns 5 values as percentiles, and returns same value after all values leaving' do
66
+ (0...2000).to_a.shuffle.each do |i|
67
+ f2._call(:enter, [i, [50,90,95,98,99].to_java(:Integer), 100].to_java)
68
+ end
69
+
70
+ expect(f2.instance_eval{ @func.valueListSize }).to eql(2000)
71
+
72
+ r = f2.getValue
73
+ expect(r.size).to eql(5)
74
+
75
+ (0...2000).to_a.shuffle.each do |i|
76
+ f2._call(:leave, [i, [50,90,95,98,99].to_java(:Integer), 100].to_java)
77
+ end
78
+
79
+ r2 = f2.getValue
80
+ expect(r2).to eql(r)
81
+ end
82
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: norikra-udf-percentile
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: java
7
+ authors:
8
+ - TAGOMORI Satoshi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: norikra
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: 0.0.9
21
+ none: false
22
+ requirement: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.9
27
+ none: false
28
+ prerelease: false
29
+ type: :runtime
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ~>
35
+ - !ruby/object:Gem::Version
36
+ version: '1.3'
37
+ none: false
38
+ requirement: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ version: '1.3'
43
+ none: false
44
+ prerelease: false
45
+ type: :development
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ version_requirements: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ none: false
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ none: false
60
+ prerelease: false
61
+ type: :development
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ none: false
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ none: false
76
+ prerelease: false
77
+ type: :development
78
+ description: This plugin adds functions named percentile/percentiles, which calculate percentile for specified fields
79
+ email:
80
+ - tagomoris@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - .ruby-version
87
+ - Gemfile
88
+ - README.md
89
+ - Rakefile
90
+ - jar/norikra-udf-percentile.jar
91
+ - java/is/tagomor/norikra/udf/Percentile.class
92
+ - java/is/tagomor/norikra/udf/Percentile.java
93
+ - java/is/tagomor/norikra/udf/PercentileFactory.class
94
+ - java/is/tagomor/norikra/udf/PercentileFactory.java
95
+ - java/is/tagomor/norikra/udf/Percentiles.class
96
+ - java/is/tagomor/norikra/udf/Percentiles.java
97
+ - java/is/tagomor/norikra/udf/PercentilesFactory.class
98
+ - java/is/tagomor/norikra/udf/PercentilesFactory.java
99
+ - lib/norikra/udf/percentile.rb
100
+ - norikra-udf-percentile.gemspec
101
+ - spec/percentile_spec.rb
102
+ - spec/percentiles_spec.rb
103
+ homepage: https://github.com/tagomoris/norikra-udf-percentile
104
+ licenses:
105
+ - GPLv2
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ - jar
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ none: false
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ none: false
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 1.8.24
126
+ signing_key:
127
+ specification_version: 3
128
+ summary: Norikra UDF percentile() and percentiles()
129
+ test_files:
130
+ - spec/percentile_spec.rb
131
+ - spec/percentiles_spec.rb