gummi 0.0.6 → 0.0.7
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.
- data/bin/console +21 -0
- data/gummi.gemspec +2 -0
- data/lib/gummi/document/attributes.rb +28 -0
- data/lib/gummi/document/search/filtered.rb +39 -0
- data/lib/gummi/document/search/raw.rb +9 -0
- data/lib/gummi/document/search/result.rb +25 -0
- data/lib/gummi/document/search/searching.rb +45 -0
- data/lib/gummi/document.rb +23 -2
- data/lib/gummi/repository/result.rb +24 -0
- data/lib/gummi/repository.rb +7 -0
- data/lib/gummi/version.rb +1 -1
- data/lib/gummi.rb +6 -5
- data/spec/lib/gummi/document_spec.rb +1 -2
- data/spec/lib/gummi/repository_spec.rb +26 -2
- data/spec/models/db/person.rb +1 -1
- data/spec/models/person.rb +4 -0
- metadata +27 -8
- data/lib/gummi/attributes.rb +0 -26
- data/lib/gummi/search/filtered.rb +0 -36
- data/lib/gummi/search/raw.rb +0 -7
- data/lib/gummi/search/result.rb +0 -23
- data/lib/gummi/search/searching.rb +0 -43
data/bin/console
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'bundler/setup'
|
3
|
+
Bundler.require
|
4
|
+
|
5
|
+
$: << ::File.expand_path('../..', __FILE__)
|
6
|
+
|
7
|
+
require 'pry'
|
8
|
+
require 'lib/gummi'
|
9
|
+
require 'spec/models/db/person'
|
10
|
+
require 'spec/models/person'
|
11
|
+
require 'spec/models/people'
|
12
|
+
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
|
13
|
+
|
14
|
+
def reload!
|
15
|
+
puts "reloading..."
|
16
|
+
Pry.save_history
|
17
|
+
exec('bin/console')
|
18
|
+
end
|
19
|
+
|
20
|
+
Pry.config.prompt = [ proc { "gummi >> " }, proc { "... >> " }]
|
21
|
+
Pry.start
|
data/gummi.gemspec
CHANGED
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_dependency('leaflet')
|
26
26
|
|
27
27
|
spec.add_development_dependency('bundler', '~> 1.3')
|
28
|
+
spec.add_development_dependency('pry')
|
29
|
+
|
28
30
|
spec.add_development_dependency('rake')
|
29
31
|
spec.add_development_dependency('rspec')
|
30
32
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Gummi
|
2
|
+
module Document
|
3
|
+
module Attributes
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
def mapping_for_attribute(attribute)
|
9
|
+
if attribute.is_a? Virtus::Attribute::EmbeddedValue
|
10
|
+
{properties: attribute.primitive.mapping}
|
11
|
+
elsif attribute.is_a? Virtus::Attribute::Collection
|
12
|
+
mapping_for_attribute(attribute.member_type)
|
13
|
+
else
|
14
|
+
attribute.mapping
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def mapping
|
19
|
+
result = {}
|
20
|
+
attribute_set.each do |attribute|
|
21
|
+
result.merge!({ attribute.name => mapping_for_attribute(attribute)})
|
22
|
+
end
|
23
|
+
result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Gummi
|
2
|
+
module Document
|
3
|
+
module Search
|
4
|
+
class Filtered
|
5
|
+
include Gummi::Document::Search::Searching
|
6
|
+
|
7
|
+
attribute :query_string, Gummi::Fields::SanitizedString
|
8
|
+
attribute :terms, Array[Hash], default: []
|
9
|
+
attribute :query_filters, Array[Hash], default: []
|
10
|
+
attribute :facets, Hash, default: {}
|
11
|
+
|
12
|
+
def to_client_args
|
13
|
+
args = {}
|
14
|
+
args[:index] = index
|
15
|
+
args[:type] = type if type
|
16
|
+
args[:from] = from
|
17
|
+
args[:body] = {query: filtered, facets: facets }
|
18
|
+
args
|
19
|
+
end
|
20
|
+
|
21
|
+
def query
|
22
|
+
{query_string: { query: query_string}} if query_string.present?
|
23
|
+
end
|
24
|
+
|
25
|
+
def filtered
|
26
|
+
{ 'filtered' => { 'query' => query, 'filter' => process_query_filters }}
|
27
|
+
end
|
28
|
+
|
29
|
+
def process_query_filters
|
30
|
+
if query_filters.length > 1
|
31
|
+
{and: query_filters}
|
32
|
+
else
|
33
|
+
query_filters.first
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Gummi
|
2
|
+
module Document
|
3
|
+
module Search
|
4
|
+
class Result
|
5
|
+
|
6
|
+
attr_reader :took, :total, :hits, :facets
|
7
|
+
|
8
|
+
def initialize(result)
|
9
|
+
@took = result["took"]
|
10
|
+
@total = result["hits"]["total"]
|
11
|
+
@hits = result["hits"]["hits"]
|
12
|
+
@facets = result["facets"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def records
|
16
|
+
hits.map do |hit|
|
17
|
+
model = "DB::#{hit["_type"].humanize}".constantize
|
18
|
+
doc_hash = {id: hit["_id"]}.merge(hit["_source"])
|
19
|
+
model.new(doc_hash)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Gummi
|
2
|
+
module Document
|
3
|
+
module Search
|
4
|
+
module Searching
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include Virtus.model
|
9
|
+
|
10
|
+
attribute :type, String
|
11
|
+
attribute :index, String, default: lambda {|search, attr| Gummi::DefaultIndex.name}
|
12
|
+
attribute :page, Gummi::Fields::PositiveInteger, default: 1
|
13
|
+
attribute :per_page, Gummi::Fields::PositiveInteger, default: 300
|
14
|
+
attribute :options, Hash, default: {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def size
|
18
|
+
per_page
|
19
|
+
end
|
20
|
+
|
21
|
+
def from
|
22
|
+
per_page * (page - 1)
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
Gummi::Document::Search::Result.new client.search(to_client_args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_client_args
|
30
|
+
args = {}
|
31
|
+
args[:index] = index
|
32
|
+
args[:type] = type if type
|
33
|
+
args[:from] = from
|
34
|
+
args[:size] = size
|
35
|
+
args.merge options
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def client
|
40
|
+
Gummi::API.client
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/gummi/document.rb
CHANGED
@@ -4,7 +4,7 @@ module Gummi
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
include Virtus.model
|
7
|
-
include Gummi::Attributes
|
7
|
+
include Gummi::Document::Attributes
|
8
8
|
end
|
9
9
|
|
10
10
|
attr_accessor :id
|
@@ -21,6 +21,17 @@ module Gummi
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
def create
|
25
|
+
response = client.create index: index.name, type: document_type, id: id, body: attributes
|
26
|
+
if response["ok"]
|
27
|
+
self.version = response["_version"]
|
28
|
+
self.id = response["_id"]
|
29
|
+
true
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
24
35
|
def update
|
25
36
|
response = client.update index: index.name, type: document_type, id: id, retry_on_conflict: 0, version: version, body: { doc: attributes.as_json }
|
26
37
|
if response["ok"]
|
@@ -47,6 +58,16 @@ module Gummi
|
|
47
58
|
|
48
59
|
module ClassMethods
|
49
60
|
|
61
|
+
def create(attributes)
|
62
|
+
document = self.new(attributes)
|
63
|
+
response = client.create index: index.name, type: document_type, id: document.id, body: document.attributes
|
64
|
+
if response["ok"]
|
65
|
+
document.version = response["_version"]
|
66
|
+
document.id = response["_id"]
|
67
|
+
document
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
50
71
|
def get!(id)
|
51
72
|
response = client.get index: index.name, type: document_type, id: id
|
52
73
|
doc_hash = {id: response["_id"], version: response["_version"]}.merge(response["_source"])
|
@@ -91,7 +112,7 @@ module Gummi
|
|
91
112
|
args[:type] = document_type
|
92
113
|
args.merge! options
|
93
114
|
|
94
|
-
Gummi::Search::Filtered.new args
|
115
|
+
Gummi::Document::Search::Filtered.new args
|
95
116
|
end
|
96
117
|
|
97
118
|
def creation_options
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Gummi
|
2
|
+
module Repository
|
3
|
+
class Result
|
4
|
+
|
5
|
+
attr_reader :took, :total, :hits, :facets
|
6
|
+
|
7
|
+
def initialize(db_result, repository, per_page, page)
|
8
|
+
@took = db_result.took
|
9
|
+
@total = db_result.total
|
10
|
+
@hits = db_result.hits
|
11
|
+
@facets = db_result.facets
|
12
|
+
@db_records = db_result.records
|
13
|
+
@repository = repository
|
14
|
+
@per_page = per_page
|
15
|
+
@page = page
|
16
|
+
end
|
17
|
+
|
18
|
+
def records
|
19
|
+
entities = Array(@repository.to_entity_from_db(@db_records)) if @db_records
|
20
|
+
Leaflet::Collection.new entities, {per_page: @per_page, current_page: @page, total_entries: total}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/gummi/repository.rb
CHANGED
@@ -16,6 +16,13 @@ module Gummi
|
|
16
16
|
to_entity_from_db record if record
|
17
17
|
end
|
18
18
|
|
19
|
+
def search(&block)
|
20
|
+
filtered_search = db_model.new_filtered_search
|
21
|
+
yield filtered_search
|
22
|
+
result = filtered_search.execute
|
23
|
+
Repository::Result.new(result, self, filtered_search.per_page, filtered_search.page)
|
24
|
+
end
|
25
|
+
|
19
26
|
def overwrite(entity)
|
20
27
|
return false unless entity.valid?
|
21
28
|
db_record = db_model.new(entity.attributes)
|
data/lib/gummi/version.rb
CHANGED
data/lib/gummi.rb
CHANGED
@@ -10,12 +10,13 @@ require "repobahn/entity"
|
|
10
10
|
|
11
11
|
require "gummi/version"
|
12
12
|
require "gummi/api"
|
13
|
-
require "gummi/attributes"
|
13
|
+
require "gummi/document/attributes"
|
14
14
|
require "gummi/document"
|
15
15
|
require "gummi/entity"
|
16
16
|
require "gummi/index"
|
17
17
|
require "gummi/object"
|
18
18
|
require "gummi/repository"
|
19
|
+
require "gummi/repository/result"
|
19
20
|
require "gummi/fields/boolean"
|
20
21
|
require "gummi/fields/time"
|
21
22
|
require "gummi/fields/integer"
|
@@ -26,10 +27,10 @@ require "gummi/fields/path_hierarchy"
|
|
26
27
|
require "gummi/fields/string"
|
27
28
|
require "gummi/fields/sanitized_string"
|
28
29
|
require "gummi/default_index"
|
29
|
-
require "gummi/search/searching"
|
30
|
-
require "gummi/search/filtered"
|
31
|
-
require "gummi/search/raw"
|
32
|
-
require "gummi/search/result"
|
30
|
+
require "gummi/document/search/searching"
|
31
|
+
require "gummi/document/search/filtered"
|
32
|
+
require "gummi/document/search/raw"
|
33
|
+
require "gummi/document/search/result"
|
33
34
|
|
34
35
|
module Gummi
|
35
36
|
def self.env
|
@@ -63,10 +63,9 @@ describe Gummi::Document do
|
|
63
63
|
end
|
64
64
|
|
65
65
|
context 'getting from elastic' do
|
66
|
-
let (:person) { DB::Person.
|
66
|
+
let (:person) { DB::Person.create(name: 'Buzz Lightyear') }
|
67
67
|
|
68
68
|
it "should return an instance of the db_model" do
|
69
|
-
person.overwrite
|
70
69
|
person_from_es = DB::Person.get(person.id)
|
71
70
|
person_from_es.should be_a DB::Person
|
72
71
|
end
|
@@ -36,10 +36,9 @@ describe Gummi::Repository do
|
|
36
36
|
describe ".get" do
|
37
37
|
context "existing record" do
|
38
38
|
|
39
|
-
let (:db_person) { DB::Person.
|
39
|
+
let (:db_person) { DB::Person.create(name: 'Buzz Lightyear') }
|
40
40
|
|
41
41
|
it "should return an entity" do
|
42
|
-
db_person.overwrite
|
43
42
|
person = People.get(db_person.id)
|
44
43
|
person.id.should == db_person.id
|
45
44
|
end
|
@@ -53,5 +52,30 @@ describe Gummi::Repository do
|
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
55
|
+
describe ".search" do
|
56
|
+
|
57
|
+
before(:each) do
|
58
|
+
DB::Person.create(name: 'Buzz Lightyear')
|
59
|
+
DB::Person.create(name: 'Woody')
|
60
|
+
Gummi::DefaultIndex.refresh
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should find the correct documents" do
|
64
|
+
result = People.search do |search|
|
65
|
+
search.query_string = "Woody"
|
66
|
+
end
|
67
|
+
result.total.should == 1
|
68
|
+
result.records.first.name.should == "Woody"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should convert the result to entities" do
|
72
|
+
result = People.search do |search|
|
73
|
+
search.query_string = "Woody"
|
74
|
+
end
|
75
|
+
woody = result.records.first
|
76
|
+
woody.converted_name.should == 'ydooW'
|
77
|
+
woody.should be_a Person
|
78
|
+
end
|
79
|
+
end
|
56
80
|
|
57
81
|
end
|
data/spec/models/db/person.rb
CHANGED
data/spec/models/person.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gummi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-11-
|
12
|
+
date: 2013-11-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: virtus
|
@@ -123,6 +123,22 @@ dependencies:
|
|
123
123
|
- - ~>
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '1.3'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: pry
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
126
142
|
- !ruby/object:Gem::Dependency
|
127
143
|
name: rake
|
128
144
|
requirement: !ruby/object:Gem::Requirement
|
@@ -157,7 +173,8 @@ dependencies:
|
|
157
173
|
version: '0'
|
158
174
|
description: A small wrapper around Elasticsearch
|
159
175
|
email:
|
160
|
-
executables:
|
176
|
+
executables:
|
177
|
+
- console
|
161
178
|
extensions: []
|
162
179
|
extra_rdoc_files: []
|
163
180
|
files:
|
@@ -166,12 +183,17 @@ files:
|
|
166
183
|
- LICENSE.txt
|
167
184
|
- README.md
|
168
185
|
- Rakefile
|
186
|
+
- bin/console
|
169
187
|
- gummi.gemspec
|
170
188
|
- lib/gummi.rb
|
171
189
|
- lib/gummi/api.rb
|
172
|
-
- lib/gummi/attributes.rb
|
173
190
|
- lib/gummi/default_index.rb
|
174
191
|
- lib/gummi/document.rb
|
192
|
+
- lib/gummi/document/attributes.rb
|
193
|
+
- lib/gummi/document/search/filtered.rb
|
194
|
+
- lib/gummi/document/search/raw.rb
|
195
|
+
- lib/gummi/document/search/result.rb
|
196
|
+
- lib/gummi/document/search/searching.rb
|
175
197
|
- lib/gummi/entity.rb
|
176
198
|
- lib/gummi/fields/boolean.rb
|
177
199
|
- lib/gummi/fields/integer.rb
|
@@ -185,10 +207,7 @@ files:
|
|
185
207
|
- lib/gummi/index.rb
|
186
208
|
- lib/gummi/object.rb
|
187
209
|
- lib/gummi/repository.rb
|
188
|
-
- lib/gummi/
|
189
|
-
- lib/gummi/search/raw.rb
|
190
|
-
- lib/gummi/search/result.rb
|
191
|
-
- lib/gummi/search/searching.rb
|
210
|
+
- lib/gummi/repository/result.rb
|
192
211
|
- lib/gummi/version.rb
|
193
212
|
- lib/repobahn/entity.rb
|
194
213
|
- lib/repobahn/repository.rb
|
data/lib/gummi/attributes.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module Gummi
|
2
|
-
module Attributes
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
module ClassMethods
|
6
|
-
|
7
|
-
def mapping_for_attribute(attribute)
|
8
|
-
if attribute.is_a? Virtus::Attribute::EmbeddedValue
|
9
|
-
{properties: attribute.primitive.mapping}
|
10
|
-
elsif attribute.is_a? Virtus::Attribute::Collection
|
11
|
-
mapping_for_attribute(attribute.member_type)
|
12
|
-
else
|
13
|
-
attribute.mapping
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def mapping
|
18
|
-
result = {}
|
19
|
-
attribute_set.each do |attribute|
|
20
|
-
result.merge!({ attribute.name => mapping_for_attribute(attribute)})
|
21
|
-
end
|
22
|
-
result
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module Gummi
|
2
|
-
module Search
|
3
|
-
class Filtered
|
4
|
-
include Gummi::Search::Searching
|
5
|
-
|
6
|
-
attribute :query_string, Gummi::Fields::SanitizedString
|
7
|
-
attribute :query_filters, Array[Hash], default: []
|
8
|
-
attribute :facets, Hash, default: {}
|
9
|
-
|
10
|
-
def to_client_args
|
11
|
-
args = {}
|
12
|
-
args[:index] = index
|
13
|
-
args[:type] = type if type
|
14
|
-
args[:from] = from
|
15
|
-
args[:body] = {query: filtered, facets: facets }
|
16
|
-
args
|
17
|
-
end
|
18
|
-
|
19
|
-
def query
|
20
|
-
{query_string: { query: query_string}} if query_string.present?
|
21
|
-
end
|
22
|
-
|
23
|
-
def filtered
|
24
|
-
{ 'filtered' => { 'query' => query, 'filter' => process_query_filters }}
|
25
|
-
end
|
26
|
-
|
27
|
-
def process_query_filters
|
28
|
-
if query_filters.length > 1
|
29
|
-
{and: query_filters}
|
30
|
-
else
|
31
|
-
query_filters.first
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/lib/gummi/search/raw.rb
DELETED
data/lib/gummi/search/result.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
module Gummi
|
2
|
-
module Search
|
3
|
-
class Result
|
4
|
-
|
5
|
-
attr_reader :took, :total, :hits, :facets
|
6
|
-
|
7
|
-
def initialize(result)
|
8
|
-
@took = result["took"]
|
9
|
-
@total = result["hits"]["total"]
|
10
|
-
@hits = result["hits"]["hits"]
|
11
|
-
@facets = result["facets"]
|
12
|
-
end
|
13
|
-
|
14
|
-
def records
|
15
|
-
hits.map do |hit|
|
16
|
-
model = "DB::#{hit["_type"].humanize}".constantize
|
17
|
-
doc_hash = {id: hit["_id"]}.merge(hit["_source"])
|
18
|
-
model.new(doc_hash)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module Gummi
|
2
|
-
module Search
|
3
|
-
module Searching
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
include Virtus.model
|
8
|
-
|
9
|
-
attribute :type, String
|
10
|
-
attribute :index, String, default: lambda {|search, attr| Gummi::DefaultIndex.name}
|
11
|
-
attribute :page, Gummi::Fields::PositiveInteger, default: 1
|
12
|
-
attribute :per_page, Gummi::Fields::PositiveInteger, default: 300
|
13
|
-
attribute :options, Hash, default: {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def size
|
17
|
-
per_page
|
18
|
-
end
|
19
|
-
|
20
|
-
def from
|
21
|
-
per_page * (page - 1)
|
22
|
-
end
|
23
|
-
|
24
|
-
def execute
|
25
|
-
Gummi::Search::Result.new client.search(to_client_args)
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_client_args
|
29
|
-
args = {}
|
30
|
-
args[:index] = index
|
31
|
-
args[:type] = type if type
|
32
|
-
args[:from] = from
|
33
|
-
args[:size] = size
|
34
|
-
args.merge options
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
def client
|
39
|
-
Gummi::API.client
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|