diametric 0.0.4 → 0.1.1
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.
- checksums.yaml +15 -0
- data/Gemfile +21 -18
- data/Jarfile +15 -1
- data/README.md +22 -14
- data/Rakefile +17 -1
- data/bin/datomic-rest +33 -0
- data/bin/download-datomic +13 -0
- data/datomic_version.yml +4 -0
- data/diametric.gemspec +9 -6
- data/ext/diametric/DiametricCollection.java +147 -0
- data/ext/diametric/DiametricConnection.java +113 -0
- data/ext/diametric/DiametricDatabase.java +107 -0
- data/ext/diametric/DiametricEntity.java +90 -0
- data/ext/diametric/DiametricListenableFuture.java +47 -0
- data/ext/diametric/DiametricObject.java +66 -0
- data/ext/diametric/DiametricPeer.java +414 -0
- data/ext/diametric/DiametricService.java +102 -0
- data/ext/diametric/DiametricUUID.java +61 -0
- data/ext/diametric/DiametricUtils.java +183 -0
- data/lib/boolean_type.rb +3 -0
- data/lib/diametric.rb +24 -0
- data/lib/diametric/entity.rb +219 -14
- data/lib/diametric/generators/active_model.rb +2 -2
- data/lib/diametric/persistence.rb +0 -1
- data/lib/diametric/persistence/common.rb +28 -9
- data/lib/diametric/persistence/peer.rb +122 -87
- data/lib/diametric/persistence/rest.rb +4 -3
- data/lib/diametric/query.rb +94 -23
- data/lib/diametric/rest_service.rb +74 -0
- data/lib/diametric/service_base.rb +77 -0
- data/lib/diametric/transactor.rb +86 -0
- data/lib/diametric/version.rb +1 -1
- data/lib/diametric_service.jar +0 -0
- data/lib/value_enums.rb +8 -0
- data/spec/conf_helper.rb +55 -0
- data/spec/config/free-transactor-template.properties +73 -0
- data/spec/config/logback.xml +59 -0
- data/spec/data/seattle-data0.dtm +452 -0
- data/spec/data/seattle-data1.dtm +326 -0
- data/spec/developer_create_sample.rb +39 -0
- data/spec/developer_query_spec.rb +120 -0
- data/spec/diametric/config_spec.rb +1 -1
- data/spec/diametric/entity_spec.rb +263 -0
- data/spec/diametric/peer_api_spec.rb +147 -0
- data/spec/diametric/persistence/peer_many2many_spec.rb +76 -0
- data/spec/diametric/persistence/peer_spec.rb +13 -22
- data/spec/diametric/persistence/rest_spec.rb +12 -19
- data/spec/diametric/query_spec.rb +4 -5
- data/spec/diametric/rest_service_spec.rb +56 -0
- data/spec/diametric/transactor_spec.rb +68 -0
- data/spec/integration_spec.rb +5 -3
- data/spec/parent_child_sample.rb +42 -0
- data/spec/peer_integration_spec.rb +106 -22
- data/spec/peer_seattle_spec.rb +200 -0
- data/spec/rc2013_seattle_big.rb +82 -0
- data/spec/rc2013_seattle_small.rb +60 -0
- data/spec/rc2013_simple_sample.rb +72 -0
- data/spec/seattle_integration_spec.rb +106 -0
- data/spec/simple_validation_sample.rb +31 -0
- data/spec/spec_helper.rb +31 -45
- data/spec/support/entities.rb +157 -0
- data/spec/support/gen_entity_class.rb +2 -0
- data/spec/support/persistence_examples.rb +9 -5
- data/spec/test_version_file.yml +4 -0
- metadata +131 -75
- data/Jarfile.lock +0 -134
- data/lib/jrclj.rb +0 -63
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'diametric/service_base'
|
2
|
+
|
3
|
+
module Diametric
|
4
|
+
class RestService
|
5
|
+
include ::Diametric::ServiceBase
|
6
|
+
class << self
|
7
|
+
def datomic_command(datomic_home)
|
8
|
+
classpath = datomic_classpath(datomic_home)
|
9
|
+
command = ["java -server -Xmx1g", "-cp", classpath, "clojure.main", "-i", "#{datomic_home}/bin/bridge.clj", "--main datomic.rest"].flatten.join(" ")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :datomic_version, :datomic_version_no, :datomic_home, :pid
|
14
|
+
attr_accessor :host, :port, :db_alias, :uri
|
15
|
+
|
16
|
+
def initialize(conf="datomic_version.yml", dest="vendor/datomic")
|
17
|
+
@conf = conf
|
18
|
+
@dest = dest
|
19
|
+
@datomic_version = RestService.datomic_version(conf)
|
20
|
+
@datomic_home = File.join(File.dirname(__FILE__), "../..", dest, @datomic_version)
|
21
|
+
@datomic_version_no = RestService.datomic_version_no(@datomic_version)
|
22
|
+
@pid = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def start(opts={})
|
26
|
+
return if @pid
|
27
|
+
RestService.download(@conf, @dest)
|
28
|
+
command = RestService.datomic_command(@datomic_home)
|
29
|
+
|
30
|
+
require 'socket'
|
31
|
+
@host = opts[:host] ? opts[:host] : Socket.gethostname
|
32
|
+
@port = opts[:port] ? opts[:port] : 9000
|
33
|
+
@db_alias = opts[:db_alias] ? opts[:db_alias] : "free"
|
34
|
+
@uri = opts[:uri] ? opts[:uri] : "datomic:mem://"
|
35
|
+
|
36
|
+
uri = URI("http://#{@host}:#{@port}/")
|
37
|
+
|
38
|
+
unless port_available?(uri)
|
39
|
+
puts "Somebody is using #{@port}. Choose other."
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
temp_pid = spawn("#{command} -p #{@port} #{@db_alias} #{@uri}")
|
44
|
+
|
45
|
+
@pid = temp_pid if ready?(uri)
|
46
|
+
end
|
47
|
+
|
48
|
+
def stop
|
49
|
+
Process.kill("HUP", @pid) if @pid
|
50
|
+
@pid = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def port_available?(uri)
|
54
|
+
response = Net::HTTP.get_response(uri)
|
55
|
+
false
|
56
|
+
rescue Errno::ECONNREFUSED
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def ready?(uri)
|
61
|
+
while true
|
62
|
+
begin
|
63
|
+
response = Net::HTTP.get_response(uri)
|
64
|
+
return true
|
65
|
+
rescue
|
66
|
+
sleep 1
|
67
|
+
redo
|
68
|
+
end
|
69
|
+
end
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'pathname'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Diametric
|
6
|
+
module ServiceBase
|
7
|
+
def self.included(base)
|
8
|
+
base.send(:extend, ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def datomic_conf_file?(file="datomic_version.yml")
|
13
|
+
if Pathname.new(file).relative?
|
14
|
+
file = File.join(File.dirname(__FILE__), "../..", file)
|
15
|
+
end
|
16
|
+
return File.exists?(file)
|
17
|
+
end
|
18
|
+
|
19
|
+
def datomic_version(conf="datomic_version.yml")
|
20
|
+
if datomic_conf_file?(conf)
|
21
|
+
datomic_names = File.read(File.join(File.dirname(__FILE__), "../..", conf))
|
22
|
+
datomic_versions = YAML.load(datomic_names)
|
23
|
+
if ENV['DIAMETRIC_ENV'] && (ENV['DIAMETRIC_ENV'] == "pro")
|
24
|
+
datomic_versions["pro"]
|
25
|
+
else
|
26
|
+
datomic_versions["free"]
|
27
|
+
end
|
28
|
+
else
|
29
|
+
conf
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def datomic_version_no(datomic_version_str)
|
34
|
+
/(\d|\.)+/.match(datomic_version_str)[0]
|
35
|
+
end
|
36
|
+
|
37
|
+
def downloaded?(conf="datomic_version.yml", dest="vendor/datomic")
|
38
|
+
datomic_home = datomic_version(conf)
|
39
|
+
if Pathname.new(dest).relative?
|
40
|
+
dest = File.join(File.dirname(__FILE__), "..", "..", dest)
|
41
|
+
end
|
42
|
+
File.exists?(File.join(dest, datomic_home))
|
43
|
+
end
|
44
|
+
|
45
|
+
def download(conf="datomic_version.yml", dest="vendor/datomic")
|
46
|
+
return true if downloaded?(conf, dest)
|
47
|
+
version = datomic_version(conf)
|
48
|
+
url = "http://downloads.datomic.com/#{datomic_version_no(version)}/#{version}.zip"
|
49
|
+
if Pathname.new(dest).relative?
|
50
|
+
dest = File.join(File.dirname(__FILE__), "../..", dest)
|
51
|
+
end
|
52
|
+
require 'open-uri'
|
53
|
+
require 'zip/zipfilesystem'
|
54
|
+
open(url) do |zip_file|
|
55
|
+
Zip::ZipFile.open(zip_file.path) do |zip_path|
|
56
|
+
zip_path.each do |zip_entry|
|
57
|
+
file_path = File.join(dest, zip_entry.to_s)
|
58
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
59
|
+
zip_path.extract(zip_entry, file_path) { true }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def datomic_classpath(datomic_home)
|
66
|
+
# Find jar archives
|
67
|
+
jars = Dir["#{datomic_home}/lib/*.jar"]
|
68
|
+
jars += Dir["#{datomic_home}/*transactor*.jar"]
|
69
|
+
|
70
|
+
# Setup CLASSPATH
|
71
|
+
classpath = jars.join(File::PATH_SEPARATOR)
|
72
|
+
files = ["samples/clj", "bin", "resources"]
|
73
|
+
classpath += File::PATH_SEPARATOR + files.collect {|f| datomic_home + "/" + f}.join(File::PATH_SEPARATOR)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'diametric/service_base'
|
2
|
+
require 'pathname'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module Diametric
|
6
|
+
class Transactor
|
7
|
+
include ::Diametric::ServiceBase
|
8
|
+
class << self
|
9
|
+
def datomic_command(datomic_home)
|
10
|
+
classpath = datomic_classpath(datomic_home)
|
11
|
+
java_opts = "-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly"
|
12
|
+
command = ["java -server -Xmx1g -Xms1g", java_opts, "-cp", classpath, "clojure.main", "--main datomic.launcher"].flatten.join(" ")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :datomic_version, :datomic_version_no, :datomic_home, :pid
|
17
|
+
attr_accessor :host, :port, :db_alias, :uri
|
18
|
+
|
19
|
+
def initialize(conf="datomic_version.yml", dest="vendor/datomic")
|
20
|
+
@conf = conf
|
21
|
+
@dest = dest
|
22
|
+
@datomic_version = Transactor.datomic_version(conf)
|
23
|
+
if Pathname.new(dest).relative?
|
24
|
+
@datomic_home = File.join(File.dirname(__FILE__), "../..", dest, @datomic_version)
|
25
|
+
else
|
26
|
+
@datomic_home = File.join(dest, @datomic_version)
|
27
|
+
end
|
28
|
+
@datomic_version_no = Transactor.datomic_version_no(@datomic_version)
|
29
|
+
@hostname = nil
|
30
|
+
@port = nil
|
31
|
+
@pid = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def start(props)
|
35
|
+
return if @pid
|
36
|
+
Transactor.download(@conf, @dest)
|
37
|
+
command = Transactor.datomic_command(@datomic_home)
|
38
|
+
|
39
|
+
unless File.exists?(props)
|
40
|
+
puts "Transactor property file #{props} doesn't exist."
|
41
|
+
return
|
42
|
+
end
|
43
|
+
properties(props)
|
44
|
+
tmp_pid = spawn("#{command} #{props}")
|
45
|
+
if ready?
|
46
|
+
@pid = tmp_pid
|
47
|
+
end
|
48
|
+
@pid
|
49
|
+
end
|
50
|
+
|
51
|
+
def stop
|
52
|
+
Process.kill("HUP", @pid) if @pid
|
53
|
+
@pid = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def properties(props)
|
57
|
+
File.readlines(props).each do |line|
|
58
|
+
m = /^(host=)(.+)/.match(line)
|
59
|
+
if m && m[2]
|
60
|
+
@hostname = m[2]
|
61
|
+
end
|
62
|
+
m = /^(port=)(\d+)/.match(line)
|
63
|
+
if m && m[2]
|
64
|
+
@port = m[2]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def ready?
|
70
|
+
tmp_database = "datomic:free://#{@hostname}:#{port}/tmp_database-#{SecureRandom.uuid}"
|
71
|
+
while true
|
72
|
+
begin
|
73
|
+
if Diametric::Persistence::Peer.create_database(tmp_database)
|
74
|
+
Diametric::Persistence::Peer.delete_database(tmp_database)
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
rescue
|
78
|
+
sleep 1
|
79
|
+
redo
|
80
|
+
end
|
81
|
+
end
|
82
|
+
true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/lib/diametric/version.rb
CHANGED
Binary file
|
data/lib/value_enums.rb
ADDED
data/spec/conf_helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
#require 'pry'
|
3
|
+
|
4
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
|
5
|
+
require 'lock_jar'
|
6
|
+
jar_file = File.join(File.dirname(__FILE__), "..", "Jarfile")
|
7
|
+
lock_file = File.join(File.dirname(__FILE__), "..", "Jarfile.lock")
|
8
|
+
LockJar.lock(jar_file)
|
9
|
+
LockJar.install(lock_file)
|
10
|
+
LockJar.load(lock_file)
|
11
|
+
end
|
12
|
+
require 'diametric'
|
13
|
+
#Dir["./spec/support/**/*.rb"].each {|f| require f}
|
14
|
+
|
15
|
+
RSpec.configure do |c|
|
16
|
+
# c.fail_fast = true
|
17
|
+
|
18
|
+
c.filter_run_excluding :integration => true unless ENV['INTEGRATION']
|
19
|
+
c.filter_run_excluding :jruby => (not is_jruby?)
|
20
|
+
c.filter_run_excluding :service => true unless ENV['RESTSERVICE']
|
21
|
+
|
22
|
+
c.filter_run_including :focused => true
|
23
|
+
c.alias_example_to :fit, :focused => true
|
24
|
+
|
25
|
+
c.run_all_when_everything_filtered = true
|
26
|
+
c.treat_symbols_as_metadata_keys_with_true_values = true
|
27
|
+
|
28
|
+
c.before(:suite) do
|
29
|
+
#@rest = Diametric::RestService.new("spec/test_version_file.cnf", "tmp/datomic")
|
30
|
+
#@rest.start(:port => 46291, :db_alias => @storage, :uri => "datomic:mem://")
|
31
|
+
#PID = @rest.pid
|
32
|
+
end
|
33
|
+
|
34
|
+
c.after(:suite) do
|
35
|
+
Diametric::Persistence::Peer.shutdown(true) if is_jruby?
|
36
|
+
#Process.kill("HUP", PID)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
shared_examples "ActiveModel" do |model|
|
41
|
+
require 'test/unit/assertions'
|
42
|
+
require 'active_model/lint'
|
43
|
+
include Test::Unit::Assertions
|
44
|
+
include ActiveModel::Lint::Tests
|
45
|
+
|
46
|
+
active_model_lints = ActiveModel::Lint::Tests.public_instance_methods.map(&:to_s).grep(/^test/)
|
47
|
+
|
48
|
+
let(:model) { subject }
|
49
|
+
|
50
|
+
active_model_lints.each do |test_name|
|
51
|
+
it "#{test_name.sub(/^test_/, '')}" do
|
52
|
+
send(test_name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
################################################################
|
2
|
+
# Basic connection settings.
|
3
|
+
|
4
|
+
protocol=free
|
5
|
+
host=localhost
|
6
|
+
port=39082
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
## OPTIONAL ####################################################
|
11
|
+
# The dev: and free: protocols typically use three ports
|
12
|
+
# starting with the selected :port, but you can specify the
|
13
|
+
# other ports explicitly, e.g. for virtualization environs
|
14
|
+
# that do not issue contiguous ports.
|
15
|
+
|
16
|
+
# h2-port=4335
|
17
|
+
# h2-web-port=4336
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
################################################################
|
22
|
+
# See http://docs.datomic.com/capacity.html
|
23
|
+
|
24
|
+
|
25
|
+
# Recommended settings for -Xmx4g, ongoing usage.
|
26
|
+
memory-index-threshold=32m
|
27
|
+
memory-index-max=128m
|
28
|
+
object-cache-max=1g
|
29
|
+
|
30
|
+
# Recommended settings for -Xmx4g import jobs.
|
31
|
+
# memory-index-threshold=512m
|
32
|
+
# memory-index-max=1g
|
33
|
+
# object-cache-max=1g
|
34
|
+
|
35
|
+
# Recommended settings for -Xmx1g usage, e.g. dev laptops.
|
36
|
+
# memory-index-threshold=32m
|
37
|
+
# memory-index-max=128m
|
38
|
+
# object-cache-max=128m
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
## OPTIONAL ####################################################
|
43
|
+
|
44
|
+
|
45
|
+
# Set to false to disable SSL between the peers and the transactor.
|
46
|
+
# Default: true
|
47
|
+
# encrypt-channel=true
|
48
|
+
|
49
|
+
# Data directory is used for dev: and free: storage, and
|
50
|
+
# as a temporary directory for all storages.
|
51
|
+
data-dir=tmp/data
|
52
|
+
|
53
|
+
# Transactor will log here, see bin/logback.xml to configure logging.
|
54
|
+
log-dir=tmp/log
|
55
|
+
|
56
|
+
# Transactor will write process pid here on startup
|
57
|
+
pid-file=tmp/transactor.pid
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
## OPTIONAL ####################################################
|
62
|
+
# See http://docs.datomic.com/capacity.html
|
63
|
+
|
64
|
+
|
65
|
+
# Soft limit on the number of concurrent writes to storage.
|
66
|
+
# Default: 4, Miniumum: 2
|
67
|
+
# write-concurrency=4
|
68
|
+
|
69
|
+
# Soft limit on the number of concurrent reads to storage.
|
70
|
+
# Default: 2 times write-concurrency, Miniumum: 2
|
71
|
+
# read-concurrency=8
|
72
|
+
|
73
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<configuration>
|
2
|
+
|
3
|
+
<!-- prevent per-message overhead for jul logging calls, e.g. Hornet -->
|
4
|
+
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
|
5
|
+
<resetJUL>true</resetJUL>
|
6
|
+
</contextListener>
|
7
|
+
|
8
|
+
<appender name="MAIN" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
9
|
+
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
10
|
+
<fileNamePattern>${DATOMIC_LOG_DIR:-log}/%d{yyyy-MM-dd}.log</fileNamePattern>
|
11
|
+
<maxHistory>72</maxHistory>
|
12
|
+
</rollingPolicy>
|
13
|
+
<prudent>true</prudent> <!-- multi jvm safe, slower -->
|
14
|
+
<encoder>
|
15
|
+
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-10contextName %logger{36} - %msg%n</pattern>
|
16
|
+
</encoder>
|
17
|
+
</appender>
|
18
|
+
|
19
|
+
<!-- uncomment to log storage access -->
|
20
|
+
<!-- <logger name="datomic.kv-cluster" level="DEBUG"/> -->
|
21
|
+
|
22
|
+
<!-- uncomment to log transactor heartbeat -->
|
23
|
+
<!-- <logger name="datomic.lifecycle" level="DEBUG"/> -->
|
24
|
+
|
25
|
+
<!-- uncomment to log transactions (transactor side) -->
|
26
|
+
<!-- <logger name="datomic.transaction" level="DEBUG"/> -->
|
27
|
+
|
28
|
+
<!-- uncomment to log transactions (peer side) -->
|
29
|
+
<!-- <logger name="datomic.peer" level="DEBUG"/> -->
|
30
|
+
|
31
|
+
<!-- uncomment to log the transactor log -->
|
32
|
+
<!-- <logger name="datomic.log" level="DEBUG"/> -->
|
33
|
+
|
34
|
+
<!-- uncomment to log peer connection to transactor -->
|
35
|
+
<!-- <logger name="datomic.connector" level="DEBUG"/> -->
|
36
|
+
|
37
|
+
<!-- uncomment to log storage gc -->
|
38
|
+
<!-- <logger name="datomic.garbage" level="DEBUG"/> -->
|
39
|
+
|
40
|
+
<!-- these namespsaces create a ton of log noise -->
|
41
|
+
<logger name="httpclient" level="INFO"/>
|
42
|
+
<logger name="org.apache.commons.httpclient" level="INFO"/>
|
43
|
+
<logger name="org.apache.http" level="INFO"/>
|
44
|
+
<logger name="org.jets3t" level="INFO"/>
|
45
|
+
<logger name="com.amazonaws" level="INFO"/>
|
46
|
+
<logger name="com.amazonaws.request" level="WARN"/>
|
47
|
+
<logger name="sun.rmi" level="INFO"/>
|
48
|
+
<logger name="net.spy.memcached" level="INFO"/>
|
49
|
+
<logger name="com.couchbase.client" level="INFO"/>
|
50
|
+
<logger name="org.apache.zookeeper" level="INFO"/>
|
51
|
+
<logger name="com.ning.http.client.providers.netty" level="INFO"/>
|
52
|
+
<logger name="org.eclipse.jetty" level="INFO"/>
|
53
|
+
<logger name="org.hornetq.core.client.impl" level="INFO"/>
|
54
|
+
<logger name="org.apache.tomcat.jdbc.pool" level="INFO"/>
|
55
|
+
|
56
|
+
<root level="info">
|
57
|
+
<appender-ref ref="MAIN"/>
|
58
|
+
</root>
|
59
|
+
</configuration>
|