bwapi 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +10 -0
- data/Gemfile +6 -0
- data/LICENCE.md +20 -0
- data/README.md +15 -0
- data/bin/bwapi +2 -0
- data/bwapi.gemspec +26 -0
- data/lib/bwapi.rb +28 -0
- data/lib/bwapi/authentication.rb +42 -0
- data/lib/bwapi/client.rb +54 -0
- data/lib/bwapi/client/admin.rb +35 -0
- data/lib/bwapi/client/admin/become.rb +21 -0
- data/lib/bwapi/client/admin/search.rb +41 -0
- data/lib/bwapi/client/admin/sub_clients.rb +109 -0
- data/lib/bwapi/client/admin/users.rb +95 -0
- data/lib/bwapi/client/admin/users/sharing.rb +35 -0
- data/lib/bwapi/client/brandwatch.rb +33 -0
- data/lib/bwapi/client/brandwatch/become.rb +19 -0
- data/lib/bwapi/client/brandwatch/client_modules.rb +26 -0
- data/lib/bwapi/client/client.rb +22 -0
- data/lib/bwapi/client/error_codes.rb +14 -0
- data/lib/bwapi/client/filters.rb +14 -0
- data/lib/bwapi/client/logout.rb +24 -0
- data/lib/bwapi/client/me.rb +42 -0
- data/lib/bwapi/client/oauth.rb +78 -0
- data/lib/bwapi/client/ping.rb +42 -0
- data/lib/bwapi/client/projects.rb +94 -0
- data/lib/bwapi/client/projects/categories.rb +70 -0
- data/lib/bwapi/client/projects/data.rb +62 -0
- data/lib/bwapi/client/projects/data_download.rb +49 -0
- data/lib/bwapi/client/projects/facebook_queries.rb +55 -0
- data/lib/bwapi/client/projects/queries.rb +99 -0
- data/lib/bwapi/client/projects/queries/backfill.rb +63 -0
- data/lib/bwapi/client/projects/queries/date_range.rb +67 -0
- data/lib/bwapi/client/projects/queries/mentions.rb +53 -0
- data/lib/bwapi/client/projects/query_groups.rb +70 -0
- data/lib/bwapi/client/projects/sharing.rb +57 -0
- data/lib/bwapi/client/projects/signals.rb +39 -0
- data/lib/bwapi/client/projects/summary.rb +21 -0
- data/lib/bwapi/client/projects/tags.rb +61 -0
- data/lib/bwapi/client/projects/users.rb +17 -0
- data/lib/bwapi/client/projects/workflow.rb +17 -0
- data/lib/bwapi/client/query_validation.rb +27 -0
- data/lib/bwapi/client/sso.rb +18 -0
- data/lib/bwapi/client/test_search.rb +14 -0
- data/lib/bwapi/client/user.rb +58 -0
- data/lib/bwapi/client/user/notifications.rb +36 -0
- data/lib/bwapi/configuration.rb +59 -0
- data/lib/bwapi/connection.rb +33 -0
- data/lib/bwapi/error.rb +42 -0
- data/lib/bwapi/request.rb +93 -0
- data/lib/bwapi/version.rb +3 -0
- data/lib/faraday/response/brandwatch_error.rb +25 -0
- data/lib/faraday/utils/utils.rb +25 -0
- data/spec/bwapi/authentication_spec.rb +57 -0
- data/spec/bwapi/client_spec.rb +205 -0
- data/spec/bwapi_spec.rb +23 -0
- data/spec/fixtures/.netrc +3 -0
- data/spec/helper.rb +12 -0
- metadata +178 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d950eb3141a3d094f3a8acda0bcc07fbaca916ca
|
4
|
+
data.tar.gz: 9461dd2860680d76e8cac1ebe9ad287095ca309b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f97eff77c439a33cb972012cce89bacccfbda6540f5022542e300e00e49f6e9741bb1c764acba767dee34f6773ff8314311fd02e1e84c19ee862983fe2888fa
|
7
|
+
data.tar.gz: fde6d236a3b0b43ea7dce59f91f2032dd83388dc5fb1aa77201aa292f60bd2c71592b0dfe21e5c4bf9f6090da406152ccdd34333531cc5d7db9e4a408cfe8f2a
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENCE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Jonathan Chrisp
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# bwapi
|
2
|
+
|
3
|
+
__PLEASE NOTE THAT THIS PROJECT IS NOT OFFICIALLY SUPPORTED BY BRANDWATCH__
|
4
|
+
|
5
|
+
A Ruby interface to the Brandwatch v2 API. The projects design is modelled on the GitHub Octokit wrapper which can be found here: https://github.com/octokit/octokit.rb.
|
6
|
+
|
7
|
+
## Tests
|
8
|
+
There are a number of unit tests which are included as part of this project which are run by rspec. Please run:
|
9
|
+
|
10
|
+
rspec spec
|
11
|
+
|
12
|
+
Please note that a number of tests still need to be added so I don't currently have complete coverage.
|
13
|
+
|
14
|
+
## Feedback
|
15
|
+
I would be more than happy to recieve feedback, please email me at: jonathan.chrisp@gmail.com
|
data/bin/bwapi
ADDED
data/bwapi.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/lib/bwapi/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'bwapi'
|
5
|
+
s.version = BWAPI::VERSION
|
6
|
+
s.date = '2013-07-24'
|
7
|
+
s.summary = 'Brandwatch v2 API Wrapper'
|
8
|
+
s.description = 'A Ruby wrapper for the Brandwatch v2 API'
|
9
|
+
s.author = 'Jonathan Chrisp'
|
10
|
+
s.email = 'jonathan@brandwatch.com'
|
11
|
+
s.license = 'MIT'
|
12
|
+
s.homepage = 'https://github.com/jonathanchrisp/bwapi'
|
13
|
+
s.required_ruby_version = ">= 1.9.2"
|
14
|
+
|
15
|
+
s.add_development_dependency 'rspec', '~> 2.13.0'
|
16
|
+
s.add_development_dependency 'pry', '~> 0.9.12.2'
|
17
|
+
|
18
|
+
s.add_runtime_dependency 'faraday', '~> 0.8.7'
|
19
|
+
s.add_runtime_dependency 'faraday_middleware', '~> 0.9.0'
|
20
|
+
s.add_runtime_dependency 'netrc', '~> 0.7.7'
|
21
|
+
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
25
|
+
s.require_paths = ['lib']
|
26
|
+
end
|
data/lib/bwapi.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'bwapi/version'
|
2
|
+
require 'bwapi/configuration'
|
3
|
+
require 'bwapi/error'
|
4
|
+
require 'bwapi/client'
|
5
|
+
|
6
|
+
module BWAPI
|
7
|
+
extend Configuration
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# Alias for BWAPI::Client.new
|
11
|
+
#
|
12
|
+
# @return [BWAPI::Client]
|
13
|
+
def new opts={}
|
14
|
+
BWAPI::Client.new opts
|
15
|
+
end
|
16
|
+
|
17
|
+
# Delegate to BWAPI::Client.new
|
18
|
+
def method_missing method, *args, &block
|
19
|
+
return super unless new.respond_to? method
|
20
|
+
new.send method, *args, &block
|
21
|
+
end
|
22
|
+
|
23
|
+
def respond_to? method, include_private=false
|
24
|
+
new.respond_to?(method, include_private) || super(method, include_private)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'netrc'
|
2
|
+
|
3
|
+
module BWAPI
|
4
|
+
module Authentication
|
5
|
+
|
6
|
+
# Check if user is authenicated
|
7
|
+
#
|
8
|
+
# @return [Boolean] Authenticated status
|
9
|
+
def authenticated?
|
10
|
+
!!access_token
|
11
|
+
end
|
12
|
+
|
13
|
+
# Check if user is a brandwatch-application-client type
|
14
|
+
#
|
15
|
+
# @return [Boolean] Application client status
|
16
|
+
def application_client?
|
17
|
+
client_id == 'brandwatch-application-client' ? true : false
|
18
|
+
end
|
19
|
+
|
20
|
+
# Check if user is a brandwatch-api-client type
|
21
|
+
#
|
22
|
+
# @return [Boolean] Application client status
|
23
|
+
def api_client?
|
24
|
+
client_id == 'brandwatch-api-client' ? true : false
|
25
|
+
end
|
26
|
+
|
27
|
+
# Set username and password via netrc
|
28
|
+
#
|
29
|
+
# @param netrc [Boolean] Netrc status
|
30
|
+
def netrc_credentials netrc=false
|
31
|
+
return unless netrc
|
32
|
+
file = Netrc.read netrc_file
|
33
|
+
|
34
|
+
# Get credentials using host
|
35
|
+
netrc_host = URI.parse(api_endpoint).host
|
36
|
+
creds = file[netrc_host]
|
37
|
+
self.username = creds.shift
|
38
|
+
self.password = creds.shift
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
data/lib/bwapi/client.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'bwapi/authentication'
|
2
|
+
require 'bwapi/connection'
|
3
|
+
require 'bwapi/request'
|
4
|
+
|
5
|
+
require 'bwapi/client/admin'
|
6
|
+
require 'bwapi/client/brandwatch'
|
7
|
+
require 'bwapi/client/client'
|
8
|
+
require 'bwapi/client/error_codes'
|
9
|
+
require 'bwapi/client/logout'
|
10
|
+
require 'bwapi/client/me'
|
11
|
+
require 'bwapi/client/oauth'
|
12
|
+
require 'bwapi/client/ping'
|
13
|
+
require 'bwapi/client/sso'
|
14
|
+
require 'bwapi/client/projects'
|
15
|
+
require 'bwapi/client/query_validation'
|
16
|
+
require 'bwapi/client/test_search'
|
17
|
+
require 'bwapi/client/user'
|
18
|
+
|
19
|
+
module BWAPI
|
20
|
+
class Client
|
21
|
+
|
22
|
+
attr_accessor *Configuration::OPTION_KEYS
|
23
|
+
|
24
|
+
def initialize opts={}
|
25
|
+
# Merge opts
|
26
|
+
opts = BWAPI.options.merge opts
|
27
|
+
|
28
|
+
# Create instance variables
|
29
|
+
Configuration::OPTION_KEYS.each do |k|
|
30
|
+
send "#{k}=", opts[k]
|
31
|
+
end
|
32
|
+
|
33
|
+
netrc_credentials opts[:netrc]
|
34
|
+
end
|
35
|
+
|
36
|
+
include BWAPI::Authentication
|
37
|
+
include BWAPI::Connection
|
38
|
+
include BWAPI::Request
|
39
|
+
|
40
|
+
include BWAPI::Client::Admin
|
41
|
+
include BWAPI::Client::Brandwatch
|
42
|
+
include BWAPI::Client::Client
|
43
|
+
include BWAPI::Client::ErrorCodes
|
44
|
+
include BWAPI::Client::Logout
|
45
|
+
include BWAPI::Client::Me
|
46
|
+
include BWAPI::Client::OAuth
|
47
|
+
include BWAPI::Client::Ping
|
48
|
+
include BWAPI::Client::Projects
|
49
|
+
include BWAPI::Client::SSO
|
50
|
+
include BWAPI::Client::QueryValidation
|
51
|
+
include BWAPI::Client::TestSearch
|
52
|
+
include BWAPI::Client::User
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'bwapi/client/admin/become'
|
2
|
+
require 'bwapi/client/admin/search'
|
3
|
+
require 'bwapi/client/admin/sub_clients'
|
4
|
+
require 'bwapi/client/admin/users'
|
5
|
+
|
6
|
+
module BWAPI
|
7
|
+
class Client
|
8
|
+
module Admin
|
9
|
+
|
10
|
+
# Get the active queries irrespective of project
|
11
|
+
#
|
12
|
+
# @param opts [Hash] options hash of parameters
|
13
|
+
# @option opts [Integer] page Page of projects to retrieve
|
14
|
+
# @option opts [Integer] pageSize Results per page of results
|
15
|
+
# @option opts [Integer] sortBy Filter to sort queries by
|
16
|
+
# @return [Hashie::Mash] All active queries
|
17
|
+
def active_queries opts={}
|
18
|
+
get "admin/activequeries", opts
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get the project report of sharing details
|
22
|
+
#
|
23
|
+
# @return [Hashie::Mash] Project sharing report
|
24
|
+
def sharing_report
|
25
|
+
get "admin/sharing-report"
|
26
|
+
end
|
27
|
+
|
28
|
+
include BWAPI::Client::Admin::Clients::Become
|
29
|
+
include BWAPI::Client::Admin::Clients::SubClients
|
30
|
+
include BWAPI::Client::Admin::Clients::Search
|
31
|
+
include BWAPI::Client::Admin::Clients::Users
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module BWAPI
|
2
|
+
class Client
|
3
|
+
module Admin
|
4
|
+
module Clients
|
5
|
+
module Become
|
6
|
+
|
7
|
+
# Become user
|
8
|
+
#
|
9
|
+
# @note must be a client admin user
|
10
|
+
#
|
11
|
+
# @param id [Integer] The user id
|
12
|
+
# @return [Hashie::Mash] User credentials
|
13
|
+
def admin_become id
|
14
|
+
get "admin/become/#{id}"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module BWAPI
|
2
|
+
class Client
|
3
|
+
module Admin
|
4
|
+
module Clients
|
5
|
+
module Search
|
6
|
+
|
7
|
+
# Get a list of queries
|
8
|
+
#
|
9
|
+
# @param opts [Hash] options hash of parameters
|
10
|
+
# @option opts [Integer] text Text expression
|
11
|
+
# @return [Hashie::Mash] List of queries
|
12
|
+
def search_query_text opts
|
13
|
+
get "admin/search/querytext"
|
14
|
+
end
|
15
|
+
alias :query_text :search_query_text
|
16
|
+
|
17
|
+
# Get a list of query names
|
18
|
+
#
|
19
|
+
# @param opts [Hash] options hash of parameters
|
20
|
+
# @option opts [Integer] text Text expression
|
21
|
+
# @return [Hashie::Mash] List of query names
|
22
|
+
def search_query_name opts
|
23
|
+
get "admin/search/queryname"
|
24
|
+
end
|
25
|
+
alias :query_name :search_query_name
|
26
|
+
|
27
|
+
# Get a list of rules
|
28
|
+
#
|
29
|
+
# @param opts [Hash] options hash of parameters
|
30
|
+
# @option opts [Integer] text Text expression
|
31
|
+
# @return [Hashie::Mash] List of rules
|
32
|
+
def search_rule_text opts
|
33
|
+
get "admin/search/ruletext"
|
34
|
+
end
|
35
|
+
alias :rule_text :search_rule_text
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module BWAPI
|
2
|
+
class Client
|
3
|
+
module Admin
|
4
|
+
module Clients
|
5
|
+
module SubClients
|
6
|
+
|
7
|
+
# Get all sub clients
|
8
|
+
#
|
9
|
+
# @param id [Integer] Id of the client
|
10
|
+
# @param opts [Hash] options hash of parameters
|
11
|
+
# @option opts [Integer] id Id of the client
|
12
|
+
# @option opts [Integer] page Page of projects to retrieve
|
13
|
+
# @option opts [Integer] pageSize Results per page of results
|
14
|
+
# @return [Hashie::Mash] All sub clients for client
|
15
|
+
def client_sub_clients id
|
16
|
+
get "admin/clients/#{id}/subclient"
|
17
|
+
end
|
18
|
+
alias :sub_clients :client_sub_clients
|
19
|
+
|
20
|
+
# Get specific sub client of client
|
21
|
+
#
|
22
|
+
# @param client_id [Integer] Id of the client
|
23
|
+
# @param sub_client_id [Integer] Id of the sub client
|
24
|
+
# @return [Hashie::Mash] Specific sub clients for client
|
25
|
+
def get_client_sub_client client_id, sub_client_id
|
26
|
+
get "admin/clients/#{client_id}/subclient/#{sub_client_id}"
|
27
|
+
end
|
28
|
+
alias :sub_client :get_client_sub_client
|
29
|
+
|
30
|
+
# Create new subclient
|
31
|
+
#
|
32
|
+
# @param id [Integer] Id of the client
|
33
|
+
# @param opts [Hash] options hash of parameters
|
34
|
+
# @option opts [Integer] clientId Current client id
|
35
|
+
# @option opts [Date] startDate Start date of the client
|
36
|
+
# @option opts [String] contactTitle Contact title of the client
|
37
|
+
# @option opts [String] address1 Address line one of the client
|
38
|
+
# @option opts [String] address2 Address line two of the client
|
39
|
+
# @option opts [String] address3 Address line three of the client
|
40
|
+
# @option opts [String] pricingModel Pricing model of the client
|
41
|
+
# @option opts [Integer] mentionArchiveSize Mention archive size for the client
|
42
|
+
# @option opts [Integer] id Id of the sub client
|
43
|
+
# @option opts [Integer] parentId Parent id of the sub client
|
44
|
+
# @option opts [Integer] maxUsers Maxiumum number of users for the client
|
45
|
+
# @option opts [Boolean] isLegacy Legacy status of the client
|
46
|
+
# @option opts [String] name Name of the client
|
47
|
+
# @option opts [String] contactTelephone Telephone number of the client
|
48
|
+
# @option opts [Integer] priceStructureId Id of the price structure for client
|
49
|
+
# @option opts [Hash] tags Tags for the client
|
50
|
+
# @option opts [String] website The website for the client
|
51
|
+
# @option opts [String] contactEmail The contact email for the client
|
52
|
+
# @option opts [Date] expiryDate The expiry date for the client
|
53
|
+
# @option opts [String] theme The theme of the client
|
54
|
+
# @option opts [Integer] priceStructureLineId The level of the price structure for the client
|
55
|
+
# @option opts [Integer] mentionBasedPricingMatrixLevel The amount of mentions allowed
|
56
|
+
# @option opts [String] postcode The postcode of the client
|
57
|
+
# @option opts [String] country The country of the client
|
58
|
+
# @option opts [String] contactName The contact name of the client
|
59
|
+
# @option opts [Integer] maximumSubscribedBrands The maximum subscribed brands for the client
|
60
|
+
# @option opts [String] contactMobile The mobile number for the client
|
61
|
+
# @return [Hashie::Mash] New sub client
|
62
|
+
def create_client_sub_client id, opts
|
63
|
+
post "admin/clients/#{id}/subclient", opts
|
64
|
+
end
|
65
|
+
alias :create_sub_client :create_client_sub_client
|
66
|
+
|
67
|
+
# Update new subclient
|
68
|
+
#
|
69
|
+
# @param client_id [Integer] Id of the client
|
70
|
+
# @param sub_client_id [Integer] Id of the sub client
|
71
|
+
# @param opts [Hash] options hash of parameters
|
72
|
+
# @option opts [Integer] clientId Current client id
|
73
|
+
# @option opts [Date] startDate Start date of the client
|
74
|
+
# @option opts [String] contactTitle Contact title of the client
|
75
|
+
# @option opts [String] address1 Address line one of the client
|
76
|
+
# @option opts [String] address2 Address line two of the client
|
77
|
+
# @option opts [String] address3 Address line three of the client
|
78
|
+
# @option opts [String] pricingModel Pricing model of the client
|
79
|
+
# @option opts [Integer] mentionArchiveSize Mention archive size for the client
|
80
|
+
# @option opts [Integer] id Id of the sub client
|
81
|
+
# @option opts [Integer] parentId Parent id of the sub client
|
82
|
+
# @option opts [Integer] maxUsers Maxiumum number of users for the client
|
83
|
+
# @option opts [Boolean] isLegacy Legacy status of the client
|
84
|
+
# @option opts [String] name Name of the client
|
85
|
+
# @option opts [String] contactTelephone Telephone number of the client
|
86
|
+
# @option opts [Integer] priceStructureId Id of the price structure for client
|
87
|
+
# @option opts [Hash] tags Tags for the client
|
88
|
+
# @option opts [String] website The website for the client
|
89
|
+
# @option opts [String] contactEmail The contact email for the client
|
90
|
+
# @option opts [Date] expiryDate The expiry date for the client
|
91
|
+
# @option opts [String] theme The theme of the client
|
92
|
+
# @option opts [Integer] priceStructureLineId The level of the price structure for the client
|
93
|
+
# @option opts [Integer] mentionBasedPricingMatrixLevel The amount of mentions allowed
|
94
|
+
# @option opts [String] postcode The postcode of the client
|
95
|
+
# @option opts [String] country The country of the client
|
96
|
+
# @option opts [String] contactName The contact name of the client
|
97
|
+
# @option opts [Integer] maximumSubscribedBrands The maximum subscribed brands for the client
|
98
|
+
# @option opts [String] contactMobile The mobile number for the client
|
99
|
+
# @return [Hashie::Mash] New sub client
|
100
|
+
def update_client_sub_client client_id, sub_client_id, opts
|
101
|
+
put "admin/clients/#{client_id}/subclient/#{sub_client_id}", opts
|
102
|
+
end
|
103
|
+
alias :update_sub_client :update_client_sub_client
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|