gooddata 0.6.19 → 0.6.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -0
- data/Rakefile +17 -3
- data/gooddata.gemspec +8 -7
- data/lib/gooddata/bricks/middleware/base_middleware.rb +1 -1
- data/lib/gooddata/cli/commands/run_ruby_cmd.rb +2 -2
- data/lib/gooddata/cli/shared.rb +2 -1
- data/lib/gooddata/commands/auth.rb +58 -5
- data/lib/gooddata/commands/runners.rb +2 -6
- data/lib/gooddata/extensions/big_decimal.rb +4 -0
- data/lib/gooddata/extensions/false.rb +11 -0
- data/lib/gooddata/extensions/hash.rb +6 -17
- data/lib/gooddata/extensions/nil.rb +11 -0
- data/lib/gooddata/extensions/numeric.rb +11 -0
- data/lib/gooddata/extensions/object.rb +11 -0
- data/lib/gooddata/extensions/symbol.rb +11 -0
- data/lib/gooddata/extensions/true.rb +11 -0
- data/lib/gooddata/helpers/auth_helpers.rb +32 -2
- data/lib/gooddata/helpers/data_helper.rb +1 -1
- data/lib/gooddata/helpers/global_helpers.rb +98 -31
- data/lib/gooddata/mixins/md_finders.rb +15 -15
- data/lib/gooddata/mixins/md_object_query.rb +12 -2
- data/lib/gooddata/models/blueprint/blueprint_field.rb +2 -2
- data/lib/gooddata/models/blueprint/dataset_blueprint.rb +2 -2
- data/lib/gooddata/models/blueprint/project_blueprint.rb +3 -3
- data/lib/gooddata/models/blueprint/schema_blueprint.rb +1 -1
- data/lib/gooddata/models/datawarehouse.rb +1 -0
- data/lib/gooddata/models/domain.rb +13 -16
- data/lib/gooddata/models/from_wire.rb +0 -2
- data/lib/gooddata/models/membership.rb +1 -1
- data/lib/gooddata/models/metadata/attribute.rb +1 -1
- data/lib/gooddata/models/metadata/dashboard.rb +1 -1
- data/lib/gooddata/models/metadata/dataset.rb +1 -1
- data/lib/gooddata/models/metadata/dimension.rb +1 -1
- data/lib/gooddata/models/metadata/fact.rb +1 -1
- data/lib/gooddata/models/metadata/label.rb +16 -17
- data/lib/gooddata/models/metadata/metric.rb +1 -1
- data/lib/gooddata/models/metadata/report.rb +1 -1
- data/lib/gooddata/models/metadata/report_definition.rb +7 -7
- data/lib/gooddata/models/metadata/variable.rb +1 -1
- data/lib/gooddata/models/model.rb +2 -2
- data/lib/gooddata/models/profile.rb +2 -2
- data/lib/gooddata/models/project.rb +21 -23
- data/lib/gooddata/models/project_role.rb +3 -3
- data/lib/gooddata/models/schedule.rb +18 -4
- data/lib/gooddata/models/user_filters/mandatory_user_filter.rb +12 -15
- data/lib/gooddata/models/user_filters/user_filter.rb +8 -8
- data/lib/gooddata/models/user_filters/user_filter_builder.rb +16 -13
- data/lib/gooddata/models/user_filters/variable_user_filter.rb +1 -1
- data/lib/gooddata/rest/client.rb +4 -2
- data/lib/gooddata/rest/connection.rb +37 -30
- data/lib/gooddata/rest/connections/rest_client_connection.rb +1 -1
- data/lib/gooddata/version.rb +1 -1
- data/spec/environment/develop.rb +4 -4
- data/spec/environment/hotfix.rb +1 -1
- data/spec/environment/release.rb +1 -1
- data/spec/integration/full_project_spec.rb +3 -3
- data/spec/integration/over_to_user_filters_spec.rb +1 -0
- data/spec/integration/project_spec.rb +1 -1
- data/spec/integration/user_filters_spec.rb +0 -1
- data/spec/unit/commands/command_auth_spec.rb +10 -0
- data/spec/unit/extensions/hash_spec.rb +1 -1
- data/spec/unit/helpers_spec.rb +0 -8
- data/spec/unit/models/domain_spec.rb +1 -9
- data/spec/unit/models/from_wire_spec.rb +1 -19
- data/spec/unit/models/membership_spec.rb +1 -1
- data/spec/unit/models/metadata_spec.rb +1 -1
- data/spec/unit/models/profile_spec.rb +23 -47
- data/spec/unit/models/schedule_spec.rb +47 -3
- metadata +174 -50
- data/lib/gooddata/models/from_wire_parse.rb +0 -125
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 393f24d2ac4d07ad718cb07a45216d0bb9ba44d6
|
4
|
+
data.tar.gz: b83bc75e78cbc105a30fc6108fc68c47fc23660b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a65998083c37fbeefd4c927917109cf203f251140569af75de4f575000aec8ce55f655128529e938fc44cdbfebfa043619ebca9d8552cd5410a5db597bc6258f
|
7
|
+
data.tar.gz: 0b29904946563a35299590595d8d07e32703e40bef0c65703376df3916720756221748f8da83ad50296737b9a6cb551c127040ac3c7d21bfc7574cd94b5598d4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,43 @@
|
|
1
1
|
# GoodData Ruby SDK Changelog
|
2
2
|
|
3
|
+
|
4
|
+
## 0.6.20
|
5
|
+
- added iterators for retrieval of project, domain, and group objects
|
6
|
+
- use query resource inlining for retrieving user filters
|
7
|
+
- added support of GoodData PGP SSO
|
8
|
+
- fixed default parameters from ~/.gooddata file (auth token, server)
|
9
|
+
- added project WebDav deprecation warning
|
10
|
+
- removed dependency on Active Support gem
|
11
|
+
|
12
|
+
## 0.6.19
|
13
|
+
- major (not backward compatible) blueprint refactoring
|
14
|
+
- added environment parameter to the project creation
|
15
|
+
- added HTTP retry strategy with exponential wait times and maximum retries set to 10
|
16
|
+
- set max concurrent platform connections set to 20 per session
|
17
|
+
- set socket timeout to 1 minute
|
18
|
+
|
19
|
+
## 0.6.18
|
20
|
+
- added support for the HYPERLINK label type in blueprint
|
21
|
+
- fixed method Schedule#create doesn't set schedule name
|
22
|
+
- added method "error?" to the class "ExecutionDetail"
|
23
|
+
- added blueprint support for folders
|
24
|
+
- added ability to change SSO provider for existing platform user
|
25
|
+
- added schedules and executions convenience methods
|
26
|
+
|
27
|
+
## 0.6.17
|
28
|
+
- added validation of the blueprint datatypes (e.g. INTEGER -> INT, allow mixed case etc.)
|
29
|
+
- improved the data loading logging and error handling
|
30
|
+
- added date dimension switching
|
31
|
+
- switched to the new asynchronous ETL pull resource
|
32
|
+
- added specification of date reference's format in blueprint
|
33
|
+
- added HTTP logging oneliner
|
34
|
+
|
35
|
+
## 0.6.16
|
36
|
+
- fixed SSL certificate validation (verify_ssl option in the GoodData.connect)
|
37
|
+
- logging changes: separated the HTTP and application logging to different levels, added platform request ID
|
38
|
+
- fixed the WebDav URI bootstrap to work with the EU datacenter
|
39
|
+
- added driver parameter for Vertica based project creation
|
40
|
+
|
3
41
|
## 0.6.15
|
4
42
|
|
5
43
|
- Adding users now accepts more variants of providing users
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ require 'rubygems'
|
|
5
5
|
require 'bundler/setup'
|
6
6
|
require 'bundler/gem_tasks'
|
7
7
|
|
8
|
-
require 'coveralls/rake/task'
|
8
|
+
# require 'coveralls/rake/task'
|
9
9
|
|
10
10
|
require 'rake/testtask'
|
11
11
|
require 'rake/notes/rake_task'
|
@@ -18,7 +18,7 @@ task :cop do
|
|
18
18
|
exec "rubocop lib/"
|
19
19
|
end
|
20
20
|
|
21
|
-
Coveralls::RakeTask.new
|
21
|
+
# Coveralls::RakeTask.new
|
22
22
|
|
23
23
|
desc 'Run continuous integration test'
|
24
24
|
task :ci do
|
@@ -27,7 +27,21 @@ task :ci do
|
|
27
27
|
Rake::Task['test:integration'].invoke
|
28
28
|
end
|
29
29
|
Rake::Task['test:cop'].invoke if RUBY_VERSION.start_with?('2.2') == false
|
30
|
-
Rake::Task['coveralls:push'].invoke
|
30
|
+
# Rake::Task['coveralls:push'].invoke
|
31
|
+
end
|
32
|
+
|
33
|
+
namespace :gem do
|
34
|
+
desc "Release gem version #{GoodData::VERSION} to rubygems"
|
35
|
+
task :release do |t|
|
36
|
+
gem = "gooddata-#{GoodData::VERSION}.gem"
|
37
|
+
|
38
|
+
puts "Building #{gem} ..."
|
39
|
+
res = system('gem build ./gooddata.gemspec')
|
40
|
+
next if !res
|
41
|
+
|
42
|
+
puts "Pushing #{gem} ..."
|
43
|
+
res = system("gem push #{gem}")
|
44
|
+
end
|
31
45
|
end
|
32
46
|
|
33
47
|
namespace :hook do
|
data/gooddata.gemspec
CHANGED
@@ -18,10 +18,12 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.summary = %q{A convenient Ruby wrapper around the GoodData RESTful API}
|
19
19
|
s.description = %q{Use the GoodData::Client class to integrate GoodData into your own application or use the CLI to work with GoodData directly from the command line.}
|
20
20
|
s.email = %q{pavel@gooddata.com}
|
21
|
-
s.executables = ['gooddata']
|
22
21
|
s.extra_rdoc_files = %w(LICENSE README.md)
|
23
22
|
|
24
23
|
s.files = `git ls-files`.split($/)
|
24
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
25
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
26
|
+
|
25
27
|
s.homepage = %q{http://github.com/gooddata/gooddata-ruby}
|
26
28
|
s.require_paths = ["lib"]
|
27
29
|
|
@@ -37,17 +39,15 @@ Gem::Specification.new do |s|
|
|
37
39
|
s.add_development_dependency 'coveralls', '~> 0.7', '>= 0.7.0'
|
38
40
|
s.add_development_dependency 'guard', '~> 2'
|
39
41
|
s.add_development_dependency 'guard-rspec', '~> 4'
|
40
|
-
s.add_development_dependency 'webmock', '~> 1.21.0'
|
41
|
-
s.add_development_dependency 'debase' if !ENV['TRAVIS_BUILD'] && RUBY_VERSION >= '2.0.0'
|
42
|
-
s.add_development_dependency 'ruby-debug-ide' if !ENV['TRAVIS_BUILD'] && RUBY_VERSION >= '2.0.0'
|
42
|
+
s.add_development_dependency 'webmock', '~> 1.21', '>= 1.21.0'
|
43
|
+
s.add_development_dependency 'debase', '~> 0.1', '>= 0.1.7' if !ENV['TRAVIS_BUILD'] && RUBY_VERSION >= '2.0.0'
|
44
|
+
s.add_development_dependency 'ruby-debug-ide', '~> 0.4' if !ENV['TRAVIS_BUILD'] && RUBY_VERSION >= '2.0.0'
|
45
|
+
s.add_development_dependency 'bundler', '~> 1.7', '>= 1.7.3'
|
43
46
|
|
44
|
-
s.add_dependency 'activesupport', '~> 4.1', '>= 4.1.0'
|
45
|
-
s.add_dependency 'bundler', '~> 1.7', '>= 1.7.3'
|
46
47
|
s.add_dependency 'docile', '~> 1.1', '>= 1.1.5'
|
47
48
|
s.add_dependency 'erubis', '~> 2.7', '>= 2.7.0'
|
48
49
|
s.add_dependency 'gli', '~> 2.12', '>= 2.12.2'
|
49
50
|
s.add_dependency 'highline', '~> 1.6', '>= 1.6.21'
|
50
|
-
s.add_dependency 'i18n', '~> 0.6', '>= 0.6.9'
|
51
51
|
s.add_dependency 'json_pure', '~> 1.8', '>= 1.8.1'
|
52
52
|
s.add_dependency 'multi_json', '~> 1.10', '>= 1.10.0'
|
53
53
|
s.add_dependency 'parseconfig', '~> 1.0', '>= 1.0.4'
|
@@ -59,4 +59,5 @@ Gem::Specification.new do |s|
|
|
59
59
|
s.add_dependency 'terminal-table', '~> 1.5', '>= 1.5.1'
|
60
60
|
s.add_dependency 'salesforce_bulk_query', '~> 0.0'
|
61
61
|
s.add_dependency 'aws-sdk', '~> 1.45'
|
62
|
+
s.add_dependency 'thread_safe'
|
62
63
|
end
|
@@ -33,7 +33,7 @@ module GoodData
|
|
33
33
|
if @config
|
34
34
|
# load it from file and merge it
|
35
35
|
defaults = { 'config' => MultiJson.load(File.read(@config)) }
|
36
|
-
default_params =
|
36
|
+
default_params = GoodData::Helpers::DeepMergeableHash[defaults]
|
37
37
|
params = default_params.deep_merge(params)
|
38
38
|
end
|
39
39
|
params
|
@@ -10,8 +10,8 @@ require_relative '../../client'
|
|
10
10
|
|
11
11
|
# translate given params (with dots) to json-like params
|
12
12
|
def load_undot(filename)
|
13
|
-
p = MultiJson.load(File.read(filename))
|
14
|
-
|
13
|
+
p = MultiJson.load(File.read(filename))
|
14
|
+
GoodData::Helper.undot(GoodData::Helper::DeepMergeableHash[p])
|
15
15
|
end
|
16
16
|
|
17
17
|
GoodData::CLI.module_eval do
|
data/lib/gooddata/cli/shared.rb
CHANGED
@@ -6,6 +6,7 @@ require_relative '../version'
|
|
6
6
|
require_relative '../core/core'
|
7
7
|
require_relative '../extensions/extensions'
|
8
8
|
require_relative '../exceptions/exceptions'
|
9
|
+
require_relative '../helpers/auth_helpers'
|
9
10
|
|
10
11
|
include GLI::App
|
11
12
|
|
@@ -30,7 +31,7 @@ GoodData::CLI.module_eval do
|
|
30
31
|
flag [:p, :project_id]
|
31
32
|
|
32
33
|
desc 'Server'
|
33
|
-
default_value GoodData::
|
34
|
+
default_value GoodData::Helpers::AuthHelper.read_server
|
34
35
|
arg_name 'server'
|
35
36
|
flag [:s, :server]
|
36
37
|
|
@@ -10,13 +10,52 @@ module GoodData
|
|
10
10
|
class Auth
|
11
11
|
class << self
|
12
12
|
# Ask for credentials
|
13
|
-
|
13
|
+
# @param [String] credentials_file_path (credentials_file) Path to .gooddata file
|
14
|
+
# @return [Hash]
|
15
|
+
# * :username [String] Username (email address)
|
16
|
+
# * :password [String] Password
|
17
|
+
# * :auth_token [String] Authorization token
|
18
|
+
# * :environment [String] Environment - DEVELOPMENT, TEST, PRODUCTION
|
19
|
+
# * :server => [String] Server - https://secure.gooddata.com
|
20
|
+
def ask_for_credentials(credentials_file_path = Helpers::AuthHelper.credentials_file)
|
14
21
|
puts 'Enter your GoodData credentials.'
|
15
|
-
user = GoodData::CLI.terminal.ask('Email')
|
16
|
-
password = GoodData::CLI.terminal.ask('Password') { |q| q.echo = 'x' }
|
17
|
-
auth_token = GoodData::CLI.terminal.ask('Authorization Token')
|
18
22
|
|
19
|
-
|
23
|
+
old_credentials = Helpers::AuthHelper.read_credentials(credentials_file_path)
|
24
|
+
|
25
|
+
# Ask for user email
|
26
|
+
user = GoodData::CLI.terminal.ask('Email') do |q|
|
27
|
+
set_default_value(q, old_credentials[:username])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Ask for password
|
31
|
+
password = GoodData::CLI.terminal.ask('Password') do |q|
|
32
|
+
# set_default_value(q, old_credentials[:password])
|
33
|
+
q.echo = '*'
|
34
|
+
end
|
35
|
+
|
36
|
+
# Ask for token
|
37
|
+
auth_token = GoodData::CLI.terminal.ask('Authorization Token') do |q|
|
38
|
+
set_default_value(q, old_credentials[:auth_token])
|
39
|
+
end
|
40
|
+
|
41
|
+
# Read environment
|
42
|
+
environment = GoodData::CLI.terminal.ask('Environment') do |q|
|
43
|
+
set_default_value(q, old_credentials[:environment], GoodData::Project::DEFAULT_ENVIRONMENT)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Read server
|
47
|
+
server = GoodData::CLI.terminal.ask('Server') do |q|
|
48
|
+
set_default_value(q, old_credentials[:server], 'https://secure.gooddata.com')
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return as struct
|
52
|
+
{
|
53
|
+
:username => user,
|
54
|
+
:password => password,
|
55
|
+
:auth_token => auth_token,
|
56
|
+
:environment => environment,
|
57
|
+
:server => server
|
58
|
+
}
|
20
59
|
end
|
21
60
|
|
22
61
|
# Ask for credentials and store them
|
@@ -40,6 +79,20 @@ module GoodData
|
|
40
79
|
def unstore(credentials_file_path = Helpers::AuthHelper.credentials_file)
|
41
80
|
Helpers::AuthHelper.remove_credentials_file(credentials_file_path)
|
42
81
|
end
|
82
|
+
|
83
|
+
# Conditionally sets default value for prompt.
|
84
|
+
# Default value is set to 'value' or 'default'
|
85
|
+
#
|
86
|
+
# @param [Highline] q Highline instance used
|
87
|
+
# @param [String] value Value used for ask default if not nil and not empty
|
88
|
+
# @param [String] default Value used for ask default iv 'value' is nil or empty
|
89
|
+
def set_default_value(q, value, default = nil)
|
90
|
+
if !value.nil? && !value.empty?
|
91
|
+
q.default = value
|
92
|
+
elsif default
|
93
|
+
q.default = default
|
94
|
+
end
|
95
|
+
end
|
43
96
|
end
|
44
97
|
end
|
45
98
|
end
|
@@ -24,7 +24,6 @@ module GoodData
|
|
24
24
|
script_body = <<-script_body
|
25
25
|
require 'fileutils'
|
26
26
|
FileUtils::cd(\"#{pwd + brick_dir}\") do\
|
27
|
-
require 'bundler/setup'
|
28
27
|
|
29
28
|
$SCRIPT_PARAMS = {
|
30
29
|
"GDC_SST" => \"#{sst}\",
|
@@ -34,13 +33,10 @@ module GoodData
|
|
34
33
|
"GDC_LOGGER_FILE" => STDOUT,
|
35
34
|
"GDC_ENV_LOCAL" => true
|
36
35
|
}.merge(#{params})
|
37
|
-
|
36
|
+
require './main.rb'
|
38
37
|
end
|
39
38
|
script_body
|
40
|
-
|
41
|
-
Bundler.with_clean_env do
|
42
|
-
system('ruby', '-e', script_body)
|
43
|
-
end
|
39
|
+
system('ruby', '-e', script_body)
|
44
40
|
end
|
45
41
|
end
|
46
42
|
end
|
@@ -1,11 +1,6 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
require 'hashie'
|
3
|
-
|
4
|
-
require 'hashie/extensions/deep_merge'
|
5
2
|
|
6
3
|
class Hash
|
7
|
-
include Hashie::Extensions::DeepMerge
|
8
|
-
|
9
4
|
# Return a hash that includes everything but the given keys. This is useful for
|
10
5
|
# limiting a set of parameters to everything but a few known toggles:
|
11
6
|
#
|
@@ -28,18 +23,12 @@ class Hash
|
|
28
23
|
self
|
29
24
|
end
|
30
25
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
k.split('__').reverse.reduce(v) do |memo, obj|
|
36
|
-
{ obj => memo }.extend(Hashie::Extensions::DeepMerge)
|
37
|
-
end
|
38
|
-
end
|
26
|
+
def slice(*keys)
|
27
|
+
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
|
28
|
+
keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if key?(k) }
|
29
|
+
end
|
39
30
|
|
40
|
-
|
41
|
-
|
42
|
-
memo.deep_merge(obj)
|
43
|
-
end
|
31
|
+
def compact
|
32
|
+
select { |_, value| !value.nil? }
|
44
33
|
end
|
45
34
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
|
-
require '
|
4
|
+
require 'json'
|
5
5
|
|
6
6
|
require_relative 'global_helpers'
|
7
7
|
|
@@ -24,10 +24,40 @@ module GoodData
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
# Try read environemnt
|
28
|
+
#
|
29
|
+
# Tries to read it from ~/.gooddata file or from environment variable GD_SERVER
|
30
|
+
# @param [String] credentials_file_path (credentials_file) Path to .gooddata file
|
31
|
+
# @return [String] server token from environment variable, .gooddata or nil
|
32
|
+
def read_environment(credentials_file_path = credentials_file)
|
33
|
+
goodfile = read_credentials(credentials_file_path)
|
34
|
+
[ENV['GD_ENVIRONMENT'], goodfile[:environment], GoodData::Project::DEFAULT_ENVIRONMENT].find { |x| !x.nil? && !x.empty? }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Try read server
|
38
|
+
#
|
39
|
+
# Tries to read it from ~/.gooddata file or from environment variable GD_SERVER
|
40
|
+
# @param [String] credentials_file_path (credentials_file) Path to .gooddata file
|
41
|
+
# @return [String] server token from environment variable, .gooddata or DEFAULT_URL
|
42
|
+
def read_server(credentials_file_path = credentials_file)
|
43
|
+
goodfile = read_credentials(credentials_file_path)
|
44
|
+
[ENV['GD_SERVER'], goodfile[:server], GoodData::Rest::Connection::DEFAULT_URL].find { |x| !x.nil? && !x.empty? }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Try read token
|
48
|
+
#
|
49
|
+
# Tries to read it from ~/.gooddata file or from environment variable GD_PROJECT_TOKEN
|
50
|
+
# @param [String] credentials_file_path (credentials_file) Path to .gooddata file
|
51
|
+
# @return [String] auth token from environment variable, .gooddata or nil
|
52
|
+
def read_token(credentials_file_path = credentials_file)
|
53
|
+
goodfile = read_credentials(credentials_file_path)
|
54
|
+
[ENV['GD_PROJECT_TOKEN'], goodfile[:auth_token], goodfile[:token]].find { |x| !x.nil? && !x.empty? }
|
55
|
+
end
|
56
|
+
|
27
57
|
# Writes credentials
|
28
58
|
def write_credentials(credentials, credentials_file_path = credentials_file)
|
29
59
|
File.open(credentials_file_path, 'w', 0600) do |f|
|
30
|
-
f.puts
|
60
|
+
f.puts JSON.pretty_generate(credentials)
|
31
61
|
end
|
32
62
|
credentials
|
33
63
|
end
|