clickmeetings 0.1.3.1 → 0.1.3.3
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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -1
- data/README.md +303 -7
- data/clickmeetings.gemspec +5 -3
- data/lib/clickmeetings.rb +6 -8
- data/lib/clickmeetings/client.rb +7 -8
- data/lib/clickmeetings/config.rb +2 -1
- data/lib/clickmeetings/engine.rb +0 -1
- data/lib/clickmeetings/model.rb +29 -19
- data/lib/clickmeetings/models/open/chat.rb +19 -0
- data/lib/clickmeetings/models/open/concerns/with_conference.rb +35 -0
- data/lib/clickmeetings/models/open/concerns/with_locale.rb +20 -0
- data/lib/clickmeetings/models/open/conference.rb +72 -0
- data/lib/clickmeetings/models/open/contact.rb +14 -0
- data/lib/clickmeetings/models/open/file_library.rb +43 -0
- data/lib/clickmeetings/models/open/invitation.rb +30 -0
- data/lib/clickmeetings/models/open/login_hash.rb +50 -0
- data/lib/clickmeetings/models/open/model.rb +38 -0
- data/lib/clickmeetings/models/open/phone_gateway.rb +9 -0
- data/lib/clickmeetings/models/open/recording.rb +22 -0
- data/lib/clickmeetings/models/open/registration.rb +20 -0
- data/lib/clickmeetings/models/open/session.rb +56 -0
- data/lib/clickmeetings/models/open/time_zone.rb +15 -0
- data/lib/clickmeetings/models/open/token.rb +35 -0
- data/lib/clickmeetings/models/privatelabel/account.rb +3 -1
- data/lib/clickmeetings/models/privatelabel/conference.rb +20 -11
- data/lib/clickmeetings/models/privatelabel/model.rb +5 -4
- data/lib/clickmeetings/models/privatelabel/profile.rb +2 -2
- data/lib/clickmeetings/storage.rb +10 -0
- data/lib/clickmeetings/version.rb +1 -1
- data/spec/clickmeetings_spec.rb +46 -0
- data/spec/client_spec.rb +27 -4
- data/spec/fixtures/delete_conferences_1_recordings.json +3 -0
- data/spec/fixtures/get_chats_1.zip +0 -0
- data/spec/fixtures/get_conferences.json +48 -0
- data/spec/fixtures/get_conferences_1.json +45 -0
- data/spec/fixtures/get_conferences_1_recordings.json +10 -0
- data/spec/fixtures/get_conferences_1_registrations.json +42 -0
- data/spec/fixtures/get_conferences_1_sessions.json +16 -0
- data/spec/fixtures/get_conferences_1_sessions_1.json +54 -0
- data/spec/fixtures/get_conferences_1_sessions_1_attendees.json +38 -0
- data/spec/fixtures/get_conferences_1_sessions_1_generate-pdf_en.json +4 -0
- data/spec/fixtures/get_conferences_1_sessions_1_generate-pdf_pl.json +5 -0
- data/spec/fixtures/get_conferences_1_sessions_1_generate-pdf_ru.json +4 -0
- data/spec/fixtures/get_conferences_1_sessions_1_registrations.json +42 -0
- data/spec/fixtures/get_conferences_1_tokens.json +254 -0
- data/spec/fixtures/get_conferences_2.json +45 -0
- data/spec/fixtures/get_conferences_active.json +1 -0
- data/spec/fixtures/get_conferences_inactive.json +1 -0
- data/spec/fixtures/get_conferences_skins.json +57 -0
- data/spec/fixtures/get_file-library_conferences_1.json +13 -0
- data/spec/fixtures/get_time_zone_list.json +422 -0
- data/spec/fixtures/get_time_zone_list_ru.json +26 -0
- data/spec/fixtures/post_conferences_1_invitation_email_en.json +1 -0
- data/spec/fixtures/post_conferences_1_invitation_email_ru.json +1 -0
- data/spec/fixtures/post_conferences_1_registration.json +6 -0
- data/spec/fixtures/post_conferences_1_room_autologin_hash.json +3 -0
- data/spec/fixtures/post_conferences_1_tokens.json +14 -0
- data/spec/fixtures/post_conferences_2_invitation_email_en.json +1 -0
- data/spec/fixtures/post_contacts.json +3 -0
- data/spec/fixtures/post_file-library.json +10 -0
- data/spec/fixtures/presentation.pdf +0 -0
- data/spec/helpers/fixtures_helpers.rb +1 -1
- data/spec/models/open/chat_spec.rb +25 -0
- data/spec/models/open/concerns/with_conference_spec.rb +55 -0
- data/spec/models/open/concerns/with_locale_spec.rb +23 -0
- data/spec/models/open/conference_spec.rb +132 -0
- data/spec/models/open/contact_spec.rb +17 -0
- data/spec/models/open/file_spec.rb +46 -0
- data/spec/models/open/invitation_spec.rb +43 -0
- data/spec/models/open/login_hash_spec.rb +59 -0
- data/spec/models/open/model_spec.rb +55 -0
- data/spec/models/open/recording_spec.rb +21 -0
- data/spec/models/open/registration_spec.rb +25 -0
- data/spec/models/open/session_spec.rb +73 -0
- data/spec/models/open/time_zone_spec.rb +27 -0
- data/spec/models/open/token_spec.rb +54 -0
- data/spec/models/privatelabel/conference_spec.rb +25 -7
- data/spec/shared_examples/tokens_examples.rb +6 -0
- data/spec/spec_helper.rb +7 -0
- metadata +147 -8
- data/lib/clickmeetings/models/open_api/.keep +0 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module Clickmeetings
|
2
|
+
module Open
|
3
|
+
class Recording < Model
|
4
|
+
include WithConference
|
5
|
+
|
6
|
+
attr_accessor :recording_duration, :recording_file_size, :recording_started, :recording_url,
|
7
|
+
:recording_start_date
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def destroy_all
|
11
|
+
res = all
|
12
|
+
|
13
|
+
Clickmeetings.with_client(client_options) do
|
14
|
+
Clickmeetings.client.delete remote_url(__method__), default_params, default_headers
|
15
|
+
end
|
16
|
+
|
17
|
+
res
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Clickmeetings
|
2
|
+
module Open
|
3
|
+
class Registration < Model
|
4
|
+
include WithConference
|
5
|
+
|
6
|
+
attr_accessor :registration_date, :registration_confirmed, :fields, :session_id,
|
7
|
+
:email, :visitor_nickname, :url, :r, :http_referer, :country, :city
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def for_session(session_id: nil)
|
11
|
+
Session.by_conference(conference_id: conference_id).new(id: session_id).registrations
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(params = {})
|
15
|
+
Conference.new(id: conference_id).register(params)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Clickmeetings
|
2
|
+
module Open
|
3
|
+
class Session < Model
|
4
|
+
include WithConference
|
5
|
+
include WithLocale
|
6
|
+
|
7
|
+
attr_accessor :total_visitors, :max_vistors, :start_date, :end_date, :attendees, :pdf,
|
8
|
+
:associations_api_key
|
9
|
+
delegate :locale, :with_locale, :find, to: :class
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def find(id)
|
13
|
+
obj = super
|
14
|
+
obj.id = id
|
15
|
+
obj
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def attendees
|
20
|
+
self.class.with_account account_api_key: associations_api_key do
|
21
|
+
Clickmeetings.with_client(client_options) do
|
22
|
+
Clickmeetings.client.get remote_url(__method__, id: id), default_params, default_headers
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_pdf(lang = nil)
|
28
|
+
self.class.with_account account_api_key: associations_api_key do
|
29
|
+
with_locale lang do
|
30
|
+
Clickmeetings.with_client(client_options) do
|
31
|
+
Clickmeetings.client.get remote_url("generate-pdf/#{locale}", id: id),
|
32
|
+
default_params, default_headers
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_report(lang = nil)
|
39
|
+
gen_pdf_response = generate_pdf(lang)
|
40
|
+
return unless gen_pdf_response["status"] == "FINISHED"
|
41
|
+
gen_pdf_response["url"] # solve this
|
42
|
+
end
|
43
|
+
|
44
|
+
def registrations
|
45
|
+
self.class.with_account account_api_key: associations_api_key do
|
46
|
+
response = Clickmeetings.with_client(client_options) do
|
47
|
+
Clickmeetings.client.get remote_url(__method__, id: id), default_params, default_headers
|
48
|
+
end
|
49
|
+
Registration.by_conference(conference_id: conference_id) do
|
50
|
+
Registration.handle_response response
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Clickmeetings
|
2
|
+
module Open
|
3
|
+
class TimeZone < Model
|
4
|
+
set_resource_name 'time_zone_list'
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def all(country: nil)
|
8
|
+
Clickmeetings.with_client(client_options) do
|
9
|
+
Clickmeetings.client.get remote_url(country), default_params, default_headers
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Clickmeetings
|
2
|
+
module Open
|
3
|
+
class Token < Model
|
4
|
+
class NoConferenceError < ::Clickmeetings::ClickmeetingError; end
|
5
|
+
|
6
|
+
include WithConference
|
7
|
+
|
8
|
+
set_resource_name "tokens"
|
9
|
+
|
10
|
+
attr_accessor :token, :sent_to_email, :first_use_date
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def all
|
14
|
+
fail NoConferenceError if conference_id.nil?
|
15
|
+
response = Clickmeetings.with_client(client_options) do
|
16
|
+
Clickmeetings.client.get remote_url(__method__), default_params, default_headers
|
17
|
+
end
|
18
|
+
handle_response response["access_tokens"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def create(params = {})
|
22
|
+
fail NoConferenceError if conference_id.nil?
|
23
|
+
response = Clickmeetings.with_client(client_options) do
|
24
|
+
Clickmeetings.client.post remote_url(__method__), params.merge(default_params), default_headers
|
25
|
+
end
|
26
|
+
handle_response response["access_tokens"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_hash(params = {})
|
31
|
+
LoginHash.create params.merge(conference_id: conference_id, token: token)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -20,7 +20,9 @@ module Clickmeetings
|
|
20
20
|
|
21
21
|
%w(enable disable).each do |m|
|
22
22
|
define_method m do
|
23
|
-
Clickmeetings.with_client(client_options)
|
23
|
+
Clickmeetings.with_client(client_options) do
|
24
|
+
client.put(remote_url(__method__, id: id), default_params)
|
25
|
+
end
|
24
26
|
@account_status = (m == "enable" ? "active" : "disabled")
|
25
27
|
self
|
26
28
|
end
|
@@ -5,36 +5,45 @@ module Clickmeetings
|
|
5
5
|
:access_type, :lobby_description, :status, :created_at,
|
6
6
|
:updated_at, :permanent_room, :ccc, :starts_at, :ends_at,
|
7
7
|
:access_role_hashes, :room_url, :phone_listener_pin,
|
8
|
-
:phone_presenter_pin, :embed_room_url, :recorder_list, :account_id
|
8
|
+
:phone_presenter_pin, :embed_room_url, :recorder_list, :account_id,
|
9
|
+
:password
|
9
10
|
|
10
11
|
class NoAccountError < ::Clickmeetings::ClickmeetingError; end
|
11
12
|
|
12
13
|
class << self
|
13
|
-
attr_reader :account_id
|
14
|
-
|
15
14
|
def by_account(account_id: nil)
|
16
|
-
|
17
|
-
|
15
|
+
Storage.cm_private_current_account = account_id
|
16
|
+
if block_given?
|
17
|
+
result = yield
|
18
|
+
Storage.cm_private_current_account = nil
|
19
|
+
result
|
20
|
+
else
|
21
|
+
self
|
22
|
+
end
|
18
23
|
end
|
19
24
|
|
20
25
|
def find(id)
|
21
|
-
fail Clickmeetings::PrivateLabel::Conference::NoAccountError if
|
26
|
+
fail Clickmeetings::PrivateLabel::Conference::NoAccountError if account_id.nil?
|
22
27
|
super
|
23
28
|
end
|
24
29
|
|
25
30
|
def all
|
26
|
-
fail Clickmeetings::PrivateLabel::Conference::NoAccountError if
|
31
|
+
fail Clickmeetings::PrivateLabel::Conference::NoAccountError if account_id.nil?
|
27
32
|
response = Clickmeetings.with_client(client_options) do
|
28
|
-
Clickmeetings.client.get remote_url(__method__)
|
33
|
+
Clickmeetings.client.get remote_url(__method__), default_params
|
29
34
|
end
|
30
|
-
response = response["active_conferences"] + response["inactive_conferences"]
|
35
|
+
response = response["active_conferences"].to_a + response["inactive_conferences"].to_a
|
31
36
|
handle_response response
|
32
37
|
end
|
33
38
|
|
34
39
|
def create(params = {})
|
35
|
-
fail Clickmeetings::PrivateLabel::Conference::NoAccountError if
|
40
|
+
fail Clickmeetings::PrivateLabel::Conference::NoAccountError if account_id.nil?
|
36
41
|
super
|
37
42
|
end
|
43
|
+
|
44
|
+
def account_id
|
45
|
+
Storage.cm_private_current_account
|
46
|
+
end
|
38
47
|
end
|
39
48
|
|
40
49
|
def initialize(params = {})
|
@@ -43,7 +52,7 @@ module Clickmeetings
|
|
43
52
|
end
|
44
53
|
|
45
54
|
def remote_url(action = nil, params = {})
|
46
|
-
|
55
|
+
"#{Account.remote_path(:find, id: @account_id)}/#{remote_path(action, params)}"
|
47
56
|
end
|
48
57
|
|
49
58
|
def update(params = {})
|
@@ -3,12 +3,13 @@ module Clickmeetings
|
|
3
3
|
class Model < ::Clickmeetings::Model
|
4
4
|
class << self
|
5
5
|
def client_options
|
6
|
-
{
|
7
|
-
url: Clickmeetings.config.privatelabel_host,
|
8
|
-
api_key: Clickmeetings.config.privatelabel_api_key
|
9
|
-
}
|
6
|
+
{ url: Clickmeetings.config.privatelabel_host }
|
10
7
|
end
|
11
8
|
end
|
9
|
+
|
10
|
+
def default_params
|
11
|
+
{ api_key: Clickmeetings.config.privatelabel_api_key }
|
12
|
+
end
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Clickmeetings
|
2
2
|
module PrivateLabel
|
3
|
-
class Profile < Model
|
3
|
+
class Profile < ::Clickmeetings::PrivateLabel::Model
|
4
4
|
attr_accessor :id, :account_manager_email, :email, :phone,
|
5
5
|
:account_manager_name, :account_manager_phone,
|
6
6
|
:name, :packages
|
@@ -11,7 +11,7 @@ module Clickmeetings
|
|
11
11
|
|
12
12
|
def get
|
13
13
|
response = Clickmeetings.with_client(client_options) do
|
14
|
-
Clickmeetings.client.get
|
14
|
+
Clickmeetings.client.get 'client', default_params, default_headers
|
15
15
|
end
|
16
16
|
handle_response response
|
17
17
|
end
|
data/spec/clickmeetings_spec.rb
CHANGED
@@ -4,4 +4,50 @@ describe Clickmeetings do
|
|
4
4
|
it 'has a version number' do
|
5
5
|
expect(Clickmeetings::VERSION).not_to be nil
|
6
6
|
end
|
7
|
+
|
8
|
+
describe '::configure' do
|
9
|
+
before do
|
10
|
+
described_class.configure do |config|
|
11
|
+
config.host = "http://teachbase.ru"
|
12
|
+
config.privatelabel_host = "http://go.teachbase.ru"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
subject { described_class.config }
|
17
|
+
|
18
|
+
it "sets config", :aggregate_failures do
|
19
|
+
expect(subject.host).to eq "http://teachbase.ru"
|
20
|
+
expect(subject.privatelabel_host).to eq "http://go.teachbase.ru"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '::reset' do
|
25
|
+
subject { described_class.reset }
|
26
|
+
|
27
|
+
context "config" do
|
28
|
+
before(:each) do
|
29
|
+
described_class.configure do |config|
|
30
|
+
config.host = "http://teachbase.ru"
|
31
|
+
config.privatelabel_host = "http://go.teachbase.ru"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "resets config" do
|
36
|
+
expect { subject }.to change { described_class.config.host }
|
37
|
+
.from("http://teachbase.ru").to("https://api.clickmeeting.com/v1")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "client" do
|
42
|
+
before(:each) do
|
43
|
+
described_class::ClientRegistry.client =
|
44
|
+
described_class::Client.new(url: "http://teachbase.ru")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "resets client" do
|
48
|
+
expect { subject }.to change { described_class.client.url }
|
49
|
+
.from("http://teachbase.ru").to("https://api.clickmeeting.com/v1")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
7
53
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -2,12 +2,10 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Clickmeetings::Client do
|
4
4
|
let(:client) do
|
5
|
-
described_class.new(url: Clickmeetings.config.privatelabel_host
|
6
|
-
api_key: Clickmeetings.config.privatelabel_api_key)
|
5
|
+
described_class.new(url: Clickmeetings.config.privatelabel_host)
|
7
6
|
end
|
8
7
|
|
9
|
-
it "should create client"
|
10
|
-
expect(subject.api_key).to eq Clickmeetings.config.api_key
|
8
|
+
it "should create client" do
|
11
9
|
expect(subject.url).to eq Clickmeetings.config.host
|
12
10
|
end
|
13
11
|
|
@@ -20,6 +18,25 @@ describe Clickmeetings::Client do
|
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
21
|
+
context "with header authorization" do
|
22
|
+
before do
|
23
|
+
stub_request(:get, "#{Clickmeetings.config.host}/ping")
|
24
|
+
.with(headers: {
|
25
|
+
'Accept'=>'*/*',
|
26
|
+
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
27
|
+
'Content-Type'=>'application/x-www-form-urlencoded',
|
28
|
+
'User-Agent'=>'Faraday v0.9.2',
|
29
|
+
'X-Api-Key'=>'qwer'
|
30
|
+
})
|
31
|
+
.to_return(status: 200, body: "{\"ping\":\"pong\"}")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "responds with pong" do
|
35
|
+
res = subject.get "ping", {}, {"X-Api-Key" => "qwer"}
|
36
|
+
expect(res).to eq({"ping" => "pong"})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
23
40
|
{
|
24
41
|
400 => Clickmeetings::BadRequestError,
|
25
42
|
401 => Clickmeetings::Unauthorized,
|
@@ -34,4 +51,10 @@ describe Clickmeetings::Client do
|
|
34
51
|
specify { expect { subject }.to raise_error error_class }
|
35
52
|
end
|
36
53
|
end
|
54
|
+
|
55
|
+
context "#request when client doesn't respond method" do
|
56
|
+
subject { client.request :set, "client" }
|
57
|
+
|
58
|
+
specify { expect { subject }.to raise_error(Clickmeetings::UndefinedHTTPMethod) }
|
59
|
+
end
|
37
60
|
end
|
Binary file
|
@@ -0,0 +1,48 @@
|
|
1
|
+
{
|
2
|
+
"active_conferences":[
|
3
|
+
{
|
4
|
+
"id":880484,
|
5
|
+
"room_type":"webinar",
|
6
|
+
"room_pin":138489866,
|
7
|
+
"name":"name",
|
8
|
+
"name_url":"name",
|
9
|
+
"starts_at":"2016-11-18T00:00:00+03:00",
|
10
|
+
"ends_at":"2016-11-18T03:00:00+03:00",
|
11
|
+
"access_type":3,
|
12
|
+
"lobby_enabled":true,
|
13
|
+
"lobby_description":"",
|
14
|
+
"registration_enabled":0,
|
15
|
+
"status":"active",
|
16
|
+
"timezone":"Europe\/Moscow",
|
17
|
+
"timezone_offset":10800,
|
18
|
+
"created_at":"2016-11-16T17:43:47+03:00",
|
19
|
+
"updated_at":"2016-11-16T21:00:24+03:00",
|
20
|
+
"permanent_room":false,
|
21
|
+
"ccc":"2016-11-17 21:00:00",
|
22
|
+
"access_role_hashes":{
|
23
|
+
"listener":"9eaf5c20ceaabe7aee532e00582ccce2",
|
24
|
+
"presenter":"fc81cc9cec28543400713900582ccce2",
|
25
|
+
"host":"5212ebf5d5f631e5e04df000582ccce2"
|
26
|
+
},
|
27
|
+
"room_url":"http:\/\/qwerewrq.anysecond.com\/name",
|
28
|
+
"phone_presenter_pin":411582,
|
29
|
+
"phone_listener_pin":823866,
|
30
|
+
"embed_room_url":"http:\/\/embed.anysecond.com\/embed_conference.html?r=16536349880484",
|
31
|
+
"widgets_hash":"cic52b",
|
32
|
+
"recorder_list":[],
|
33
|
+
"settings":{
|
34
|
+
"show_on_personal_page":true,
|
35
|
+
"thank_you_emails_enabled":true,
|
36
|
+
"connection_tester_enabled":false,
|
37
|
+
"recorder_autostart_enabled":false,
|
38
|
+
"room_invite_button_enabled":true,
|
39
|
+
"social_media_sharing_enabled":false,
|
40
|
+
"connection_status_enabled":true
|
41
|
+
},
|
42
|
+
"autologin_hashes":{
|
43
|
+
"host":"BQtjAQt0DUjgsROxnaWyDTEdpzHhMTcNsP18DTEdpzIlnzIxDUjgsRONsP18DQHlZGWlo3Z1pGImAwZkpwIlZQEkpmNjZQH4ZaOjpUVlDUjgsRN__"
|
44
|
+
},
|
45
|
+
"autologin_hash":"BQtjAQt0DUjgsROxnaWyDTEdpzHhMTcNsP18DTEdpzIlnzIxDUjgsRONsP18DQHlZGWlo3Z1pGImAwZkpwIlZQEkpmNjZQH4ZaOjpUVlDUjgsRN__"
|
46
|
+
}
|
47
|
+
]
|
48
|
+
}
|