diametric 0.1.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +28 -0
  3. data/Jarfile +20 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +264 -0
  6. data/Rakefile +49 -0
  7. data/bin/datomic-rest +33 -0
  8. data/bin/download-datomic +13 -0
  9. data/datomic_version.yml +4 -0
  10. data/diametric-java.gemspec +39 -0
  11. data/ext/diametric/DiametricCollection.java +147 -0
  12. data/ext/diametric/DiametricConnection.java +113 -0
  13. data/ext/diametric/DiametricDatabase.java +107 -0
  14. data/ext/diametric/DiametricEntity.java +90 -0
  15. data/ext/diametric/DiametricListenableFuture.java +47 -0
  16. data/ext/diametric/DiametricObject.java +66 -0
  17. data/ext/diametric/DiametricPeer.java +414 -0
  18. data/ext/diametric/DiametricService.java +102 -0
  19. data/ext/diametric/DiametricUUID.java +61 -0
  20. data/ext/diametric/DiametricUtils.java +183 -0
  21. data/lib/boolean_type.rb +3 -0
  22. data/lib/diametric.rb +42 -0
  23. data/lib/diametric/config.rb +54 -0
  24. data/lib/diametric/config/environment.rb +42 -0
  25. data/lib/diametric/entity.rb +659 -0
  26. data/lib/diametric/errors.rb +13 -0
  27. data/lib/diametric/generators/active_model.rb +42 -0
  28. data/lib/diametric/persistence.rb +48 -0
  29. data/lib/diametric/persistence/common.rb +82 -0
  30. data/lib/diametric/persistence/peer.rb +154 -0
  31. data/lib/diametric/persistence/rest.rb +107 -0
  32. data/lib/diametric/query.rb +259 -0
  33. data/lib/diametric/railtie.rb +52 -0
  34. data/lib/diametric/rest_service.rb +74 -0
  35. data/lib/diametric/service_base.rb +77 -0
  36. data/lib/diametric/transactor.rb +86 -0
  37. data/lib/diametric/version.rb +3 -0
  38. data/lib/diametric_service.jar +0 -0
  39. data/lib/tasks/create_schema.rb +27 -0
  40. data/lib/tasks/diametric_config.rb +45 -0
  41. data/lib/value_enums.rb +8 -0
  42. data/spec/conf_helper.rb +55 -0
  43. data/spec/config/free-transactor-template.properties +73 -0
  44. data/spec/config/logback.xml +59 -0
  45. data/spec/data/seattle-data0.dtm +452 -0
  46. data/spec/data/seattle-data1.dtm +326 -0
  47. data/spec/developer_create_sample.rb +39 -0
  48. data/spec/developer_query_spec.rb +120 -0
  49. data/spec/diametric/config_spec.rb +60 -0
  50. data/spec/diametric/entity_spec.rb +476 -0
  51. data/spec/diametric/peer_api_spec.rb +147 -0
  52. data/spec/diametric/persistence/peer_many2many_spec.rb +76 -0
  53. data/spec/diametric/persistence/peer_spec.rb +27 -0
  54. data/spec/diametric/persistence/rest_spec.rb +30 -0
  55. data/spec/diametric/persistence_spec.rb +59 -0
  56. data/spec/diametric/query_spec.rb +118 -0
  57. data/spec/diametric/rest_service_spec.rb +56 -0
  58. data/spec/diametric/transactor_spec.rb +68 -0
  59. data/spec/integration_spec.rb +107 -0
  60. data/spec/parent_child_sample.rb +42 -0
  61. data/spec/peer_integration_spec.rb +121 -0
  62. data/spec/peer_seattle_spec.rb +200 -0
  63. data/spec/rc2013_seattle_big.rb +82 -0
  64. data/spec/rc2013_seattle_small.rb +60 -0
  65. data/spec/rc2013_simple_sample.rb +72 -0
  66. data/spec/seattle_integration_spec.rb +106 -0
  67. data/spec/simple_validation_sample.rb +31 -0
  68. data/spec/spec_helper.rb +63 -0
  69. data/spec/support/entities.rb +157 -0
  70. data/spec/support/gen_entity_class.rb +9 -0
  71. data/spec/support/persistence_examples.rb +104 -0
  72. data/spec/test_version_file.yml +4 -0
  73. metadata +290 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 87aa3d4e00a0b4f5ffbc7e06710d8bfaeddc318b
4
+ data.tar.gz: 8a5f18c2e823279ce54471a89b336670a5a6219e
5
+ SHA512:
6
+ metadata.gz: 54e3e57bfad6731d7c09dbf23a6cc79e84becd30b0e9396171fe945c9a4b8e94351a4eb0795ec6e3a8e944d8ca636f4b13cf287821808975d82878427fac7c01
7
+ data.tar.gz: abd9bd9e3f162db5e6dd070c496f6f6363dc09fb6c573689b4f754b799dbe643a0e9b9e5fba880af7acd90efa143307cbc85576b6cb219ea174c2beb6dc549c8
data/Gemfile ADDED
@@ -0,0 +1,28 @@
1
+ # -*- ruby -*-
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'edn', '~> 1.0.2'
6
+ gem 'activesupport', '~> 3.2.14'
7
+ gem 'activemodel', '~> 3.2.14'
8
+ gem 'datomic-client', '~> 0.4.1'
9
+ gem 'rubyzip', '~> 0.9.9'
10
+
11
+ gem 'lock_jar', '~> 0.7.5', :platform => :jruby
12
+ gem 'jruby-openssl', '~> 0.8.8', :platform => :jruby
13
+ gem 'uuid', '~> 2.3.7'
14
+
15
+ gem 'rspec', '~> 2.14.1'
16
+ gem 'pry', '~> 0.9.12.2'
17
+
18
+ group :test, :development do
19
+ gem 'rake-compiler', '~> 0.9.1', :platform => :jruby
20
+ gem 'guard', '~> 1.8.2'
21
+ gem 'guard-rspec', '~> 3.0.2'
22
+ gem 'rb-inotify', :platform => :mri
23
+ gem 'rb-fsevent', :platform => :mri
24
+ gem 'rb-fchange', :platform => :mri
25
+ gem 'yard', :platform => :mri
26
+ gem 'redcarpet', :platform => :mri
27
+ end
28
+
data/Jarfile ADDED
@@ -0,0 +1,20 @@
1
+ repository 'http://clojars.org/repo/'
2
+ repository 'https://repository.jboss.org/nexus/content/groups/public/'
3
+ repository 'http://files.couchbase.com/maven2/'
4
+
5
+ datomic_names = File.read(File.join(File.dirname(__FILE__), "datomic_version.yml"))
6
+ require 'yaml'
7
+ datomic_versions = YAML.load(datomic_names)
8
+
9
+ if ENV['DIAMETRIC_ENV'] && (ENV['DIAMETRIC_ENV'] == "pro")
10
+ datomic_version = datomic_versions["pro"]
11
+ else
12
+ datomic_version = datomic_versions["free"]
13
+ end
14
+ version = /(\d|\.)+/.match(datomic_version)[0]
15
+ datomic_version.slice!(version)
16
+ artifactId = datomic_version.chop
17
+
18
+ group :default, :runtime do
19
+ jar "com.datomic:#{artifactId}:#{version}"
20
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Clinton N. Dreisbach
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,264 @@
1
+ [![Build Status](https://secure.travis-ci.org/relevance/diametric.png)](http://travis-ci.org/relevance/diametric)
2
+
3
+ # Diametric
4
+
5
+ Diametric is a library for building schemas, queries, and transactions
6
+ for [Datomic][] from Ruby objects. It is also used to map Ruby objects
7
+ as entities into a Datomic database.
8
+
9
+ ## Thanks
10
+
11
+ Development of Diametric was sponsored by [Relevance][]. They are the
12
+ best Clojure shop around and one of the best Ruby shops. I highly
13
+ recommend them for help with your corporate projects.
14
+
15
+ Special thanks to Mongoid for writing some solid ORM code that was liberally borrowed from to add Rails support to Diametric.
16
+
17
+ ## Documents
18
+
19
+ Other than highlights below, there are documents on Wiki.
20
+
21
+ - [Getting Started](https://github.com/relevance/diametric/wiki/Getting-Started)
22
+ - [Rails Integration](https://github.com/relevance/diametric/wiki/Rails-Integration-%28Experimental%29)
23
+ - [Seattle Example](https://github.com/relevance/diametric/wiki/Seattle-Example)
24
+
25
+
26
+ ## Entity API
27
+
28
+ The `Entity` module is interesting, in that it is primarily made of
29
+ pure functions that take their receiver (an instance of the class they
30
+ are included in) and return data that you can use in Datomic. This
31
+ makes it not an ORM-like thing at all, but instead a Ruby-ish data
32
+ builder for Datomic. And yet, a `Diametric::Entity` is fully
33
+ `ActiveModel` compliant! You can use them anywhere you would use an
34
+ `ActiveRecord` model or another `ActiveModel`-compliant instance.
35
+
36
+ They do not include all `ActiveModel` modules by default, only the
37
+ ones needed to establish compliance. You may want to include others
38
+ yourself, such as `Validations` or `Callbacks`.
39
+
40
+ ```ruby
41
+ require 'diametric'
42
+
43
+ class Person
44
+ include Diametric::Entity
45
+
46
+ attribute :name, String, :index => true
47
+ attribute :email, String, :cardinality => :many
48
+ attribute :birthday, DateTime
49
+ attribute :iq, Integer
50
+ end
51
+
52
+ # To see what schema data will be produced:
53
+ Person.schema
54
+
55
+ # The schema will be mapped to Datomic transaction data below:
56
+ # [{:db/id #db/id[:db.part/db]
57
+ # :db/ident :person/name
58
+ # :db/valueType :db.type/string
59
+ # :db/cardinality :db.cardinality/one
60
+ # :db/index true
61
+ # :db.install/_attribute :db.part/db}
62
+ # {:db/id #db/id[:db.part/db]
63
+ # :db/ident :person/email
64
+ # :db/valueType :db.type/string
65
+ # :db/cardinality :db.cardinality/many
66
+ # :db.install/_attribute :db.part/db}
67
+ # {:db/id #db/id[:db.part/db]
68
+ # :db/ident :person/birthday
69
+ # :db/valueType :db.type/instant
70
+ # :db/cardinality :db.cardinality/one
71
+ # :db.install/_attribute :db.part/db}
72
+ # {:db/id #db/id[:db.part/db]
73
+ # :db/ident :person/iq
74
+ # :db/valueType :db.type/long
75
+ # :db/cardinality :db.cardinality/one
76
+ # :db.install/_attribute :db.part/db}]
77
+
78
+ # To check what attributes are in Person model:
79
+ Person.attributes.keys
80
+ # [:dbid, :name, :email, :birthday, :iq]
81
+
82
+ # To create an instance from a query result
83
+ person = Person.new(Hash[*(Person.attributes.zip(results_from_query).flatten)])
84
+ # or
85
+ person = Person.from_query(results_from_query)
86
+
87
+ # To update/set values of a model:
88
+ person.iq = 180
89
+
90
+ # Below will help to understand what transaction data will be produced:
91
+ person.tx_data(:iq)
92
+
93
+ # It will be mapped to the Datomic transaction data:
94
+ # [{:db/id person.dbid
95
+ # :person/iq 180}]
96
+
97
+ # To create new model instance:
98
+ person = Person.new(:name => "Peanut")
99
+ person.tx_data
100
+ # Datomic transaction data will be:
101
+ # [{:db/id #db/id[:db.part/user]
102
+ # :person/name "Peanut"}]
103
+ ```
104
+
105
+ In addition to `attribute`, Diametric supports `enum` type. This is often used on Datomic.
106
+ For details, see [Seattle Example](https://github.com/relevance/diametric/wiki/Seattle-Example)
107
+
108
+ ## Query API
109
+
110
+ The query API is used for generating Datomic queries, whether to send via an external client or via the persistence API. The two methods used to generate a query are `.where` and `.filter`, both of which are chainable.
111
+
112
+ To get query data and args for a query, call `.data` on a `Query`.
113
+
114
+ If you are using a persistence API, you can ask `Query` to get the results of a Datomic query. `Diametric::Query` is an `Enumerable`. To get the results of a query, use `Enumerable` methods such as `.each` or `.first`. `Query` also provides a `.all` method to run the query and get the results.
115
+
116
+ ```ruby
117
+ query = Datomic::Query.new(Person).where(:name => "Clinton Dreisbach")
118
+ query.data
119
+ # Datomic query:
120
+ # [:find ?e ?name ?email ?birthday ?iq ?website
121
+ # :from $ ?name
122
+ # :where [?e :person/name ?name]
123
+ # [?e :person/email ?email]
124
+ # [?e :person/birthday ?birthday]
125
+ # [?e :person/iq ?iq]
126
+ # [?e :person/website ?website]]
127
+ # Args:
128
+ # ["Clinton Dreisbach"]
129
+ #
130
+ # Returns as an array, [query, args].
131
+
132
+ query = Datomic::Query.new(Person).where(:name => "Clinton Dreisbach").filter(:>, :iq, 150)
133
+ query.data
134
+ # Datomic query:
135
+ # [:find ?e ?name ?email ?birthday ?iq ?website
136
+ # :from $ ?name
137
+ # :where [?e :person/name ?name]
138
+ # [?e :person/email ?email]
139
+ # [?e :person/birthday ?birthday]
140
+ # [?e :person/iq ?iq]
141
+ # [?e :person/website ?website]
142
+ # [> ?iq 150]
143
+ # Args:
144
+ # ["Clinton Dreisbach"]
145
+ #
146
+ # Returns as an array, [query, args].
147
+ ```
148
+
149
+ ## Persistence API
150
+
151
+ The persistence API comes in two flavors: REST- and Peer-based.
152
+ Although REST-bases API supports CRUD operations like a legacy RDBMS,
153
+ it is a subset of Peer-based API.
154
+
155
+ The suitable persistent module will be selected based on URI to connect datomic.
156
+ You don't need to care which module should be included.
157
+ However, if you like to inlcude REST or Peer module explicitely, you can write it.
158
+
159
+
160
+ ### Peer
161
+
162
+ With Peer connection, you can create objects that know how to store themselves to Datomic through a Datomic Peer.
163
+
164
+ Peer connection as well as "require `diametric/persistence/peer`" are only available on JRuby.
165
+ When you install the `diametric` gem with JRuby, all `.jar` files needed to run Datomic will be downloaded.
166
+
167
+ ```ruby
168
+ require 'diametric'
169
+ require 'diametric/persistence'
170
+
171
+ # database URI
172
+ # will create database if it does not already exist
173
+ Diametric::Persistence.establish_base_connection({:uri=>'datomic:mem://sample'})
174
+ ```
175
+
176
+ ### REST
177
+
178
+ With REST connection, you can create objects that know how to store themselves to Datomic through the Datomic REST API.
179
+ REST connection is available both on CRuby and JRuby.
180
+ You need to download Datomic by yourself and start the server before you run the code.
181
+
182
+ ```ruby
183
+ require 'diametric'
184
+ require 'diametric/persistence'
185
+
186
+ # database url, database alias, database name
187
+ # will create database if it does not already exist
188
+ Diametric::Persistence.establish_base_connection({:uri => 'http://localhost:9000', :storage => 'free', :database => 'sample'})
189
+ ```
190
+
191
+ ### Using persisted models
192
+
193
+ ```ruby
194
+ class Goat
195
+ include Diametric::Entity
196
+ include Diametric::Persistence
197
+
198
+ attribute :name, String, :index => true
199
+ attribute :age, Integer
200
+ end
201
+
202
+ goat = Goat.new(:name => 'Beans', :age => 2)
203
+ goat.dbid # => nil
204
+ goat.name # => "Beans"
205
+ goat.persisted? # => false
206
+ goat.new? # => true
207
+
208
+ goat.save
209
+ goat.dbid # => new id autogenerated
210
+ goat.name # => "Beans"
211
+ goat.persisted? # => true
212
+ goat.new? # => false
213
+
214
+ goats = Goat.where(:name => "Beans")
215
+ #=> [Goat(id: 1, age: 2, name: "Beans")]
216
+
217
+ goat = Goat.first(:name => "Beans")
218
+ #=> Goat(id: 1, age: 2, name: "Beans")
219
+
220
+ goats = Goat.filter(:<, :age, 3)
221
+ #=> [Goat(id: 1, age: 2, name: "Beans")]
222
+
223
+ goats = Goat.filter(:>, :age, 3)
224
+ #=> []
225
+ ```
226
+
227
+ ## Installation
228
+
229
+ Add this line to your application's Gemfile:
230
+
231
+ gem 'diametric'
232
+
233
+ And then execute:
234
+
235
+ $ bundle
236
+
237
+ Or install it yourself as:
238
+
239
+ $ gem install diametric
240
+
241
+ ## Contributing
242
+
243
+ 1. Fork it
244
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
245
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
246
+ 4. Push to the branch (`git push origin my-new-feature`)
247
+ 5. Create new Pull Request
248
+
249
+ ## License
250
+
251
+ This project uses the [BSD License][].
252
+
253
+ Copyright (c) 2012, Clinton Dreisbach & Relevance Inc. All rights reserved.
254
+
255
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
256
+
257
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
258
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
259
+
260
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
261
+
262
+ [Datomic]: http://www.datomic.com
263
+ [Relevance]: http://www.thinkrelevance.com
264
+ [BSD License]: http://opensource.org/licenses/BSD-2-Clause
@@ -0,0 +1,49 @@
1
+ begin
2
+ require 'rake'
3
+ require 'rspec/core/rake_task'
4
+ rescue LoadError
5
+ end
6
+
7
+
8
+ task :default => :prepare
9
+
10
+ task :prepare => :install_lockjar do
11
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
12
+ require 'lock_jar'
13
+
14
+ # get jarfile relative the gem dir
15
+ lockfile = File.expand_path("../Jarfile.lock", __FILE__)
16
+
17
+ LockJar.install(lockfile)
18
+ end
19
+ end
20
+
21
+ task :install_lockjar do
22
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
23
+ require 'rubygems'
24
+ require 'rubygems/dependency_installer'
25
+ inst = Gem::DependencyInstaller.new
26
+ inst.install 'lock_jar', '~> 0.7.2'
27
+ end
28
+ end
29
+
30
+ desc "Run all RSpec tests"
31
+ require 'rspec'
32
+ require 'rspec/core/rake_task'
33
+ RSpec::Core::RakeTask.new(:spec)
34
+
35
+
36
+ # setting for rake compiler
37
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
38
+ require 'lock_jar'
39
+ LockJar.lock
40
+ locked_jars = LockJar.load
41
+
42
+ require 'rake/javaextensiontask'
43
+ Rake::JavaExtensionTask.new('diametric') do |ext|
44
+ jruby_home = ENV['MY_RUBY_HOME'] # this is available of rvm
45
+ jars = ["#{jruby_home}/lib/jruby.jar"] + FileList['lib/*.jar'] + locked_jars
46
+ ext.classpath = jars.map {|x| File.expand_path x}.join ':'
47
+ ext.name = 'diametric_service'
48
+ end
49
+ end
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ options = {}
5
+
6
+ opts = OptionParser.new do |opts|
7
+ opts.define_head "Usage: datomic-rest -p port -a db_alias -u uri"
8
+ opts.separator ""
9
+ opts.separator "Example:"
10
+ opts.separator " datomc-rest -p 9000 -a free -u datomic:mem://"
11
+
12
+ opts.on("-p", "--port [port]", Integer, "Port number") do |v|
13
+ options[:port] = v
14
+ end
15
+
16
+ opts.on("-a", "--alias [alias]", String, "Alias name") do |v|
17
+ options[:db_alias] = v
18
+ end
19
+
20
+ opts.on("-u", "--uri [uri]", String, "URI") do |v|
21
+ options[:uri] = v
22
+ end
23
+ end
24
+ opts.parse!
25
+
26
+ DATOMIC_NAME = File.read(File.join(File.dirname(__FILE__), "..", "datomic_version.cnf"))
27
+
28
+ require 'diametric/rest_service'
29
+
30
+ service = Diametric::RestService.new
31
+ PID = service.start(options)
32
+
33
+ puts "Datomic REST service is running (PID = #{PID})" unless PID.nil?
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ DATOMIC_NAME = File.read(File.join(File.dirname(__FILE__), "..", "datomic_version.cnf"))
4
+
5
+ require 'diametric/rest_service'
6
+
7
+ if Diametric::RestService.downloaded?
8
+ puts "Datomic #{DATOMIC_NAME} is already present in vendor/datomic"
9
+ else
10
+ puts "Now, downloading..."
11
+ Diametric::RestService.download
12
+ puts "Done. #{DATOMIC_NAME} has been downloaded in vendor/datomic"
13
+ end
@@ -0,0 +1,4 @@
1
+ free:
2
+ datomic-free-0.8.4122
3
+ pro:
4
+ datomic-pro-0.8.4122