norikra-udf-percentile 0.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -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