panda 1.4.4 → 1.5.0
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/CHANGELOG.md +13 -1
- data/README.md +4 -4
- data/lib/panda.rb +1 -2
- data/lib/panda/adapters/adapter.rb +2 -0
- data/lib/panda/adapters/faraday.rb +5 -5
- data/lib/panda/adapters/restclient.rb +10 -23
- data/lib/panda/base.rb +9 -3
- data/lib/panda/panda.rb +1 -1
- data/lib/panda/proxies/encoding_scope.rb +9 -1
- data/lib/panda/proxies/scope.rb +1 -1
- data/lib/panda/resources/encoding.rb +26 -3
- data/lib/panda/resources/video.rb +18 -3
- data/lib/panda/version.rb +1 -1
- data/panda.gemspec +5 -4
- data/spec/encoding_spec.rb +2 -2
- data/spec/video_spec.rb +8 -3
- metadata +41 -26
- data/lib/panda/modules/viewable.rb +0 -19
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,19 @@
|
|
1
|
+
## 1.5.0 (October 17, 2011)
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- Faraday and Typhoeus by default
|
6
|
+
- MultiJson
|
7
|
+
- Added `urls`
|
8
|
+
- Removed `screenshots` on video replaced by preview_url
|
9
|
+
- Nicer inspect on resources
|
10
|
+
- Added `metadata` on video and `cancel` and `retry` on encoding
|
11
|
+
- Added direct access to a specific encoding using video.encodings['h264'] (if profile_name is h264)
|
12
|
+
|
1
13
|
## 1.4.4 (August 25, 2011)
|
2
14
|
|
3
15
|
Features:
|
4
|
-
Updated the faraday interface to use
|
16
|
+
- Updated the faraday interface to use Typhoeus and recent Faraday
|
5
17
|
|
6
18
|
## 1.4.3 (August 18, 2011)
|
7
19
|
|
data/README.md
CHANGED
@@ -19,8 +19,8 @@ Panda gem provides an interface to access the [Panda](http://pandastream.com) AP
|
|
19
19
|
access_key "panda_access_key"
|
20
20
|
secret_key "panda_secret_key"
|
21
21
|
cloud_id "panda_cloud_id"
|
22
|
-
#
|
23
|
-
#
|
22
|
+
# Uncomment below if you have register for an EU account
|
23
|
+
# api_host "api-eu.pandastream.com"
|
24
24
|
end
|
25
25
|
|
26
26
|
or Panda.configure({:access_key => ....})
|
@@ -50,8 +50,8 @@ The name of the profile can be found in your [Panda account](http://pandastream.
|
|
50
50
|
encodings = Panda::Video.find("1234").encodings
|
51
51
|
=> [...]
|
52
52
|
|
53
|
-
mp4_encoding = encodings
|
54
|
-
ogg_encoding = encodings
|
53
|
+
mp4_encoding = encodings["h264"]
|
54
|
+
ogg_encoding = encodings["ogg"]
|
55
55
|
|
56
56
|
mp4_encoding.url
|
57
57
|
=> "http://s3.amazonaws.com/my_panda_bucket/4567.mp4"
|
data/lib/panda.rb
CHANGED
@@ -8,7 +8,6 @@ require 'panda/modules/builders'
|
|
8
8
|
require 'panda/modules/destroyers'
|
9
9
|
require 'panda/modules/associations'
|
10
10
|
require 'panda/modules/updatable'
|
11
|
-
require 'panda/modules/viewable'
|
12
11
|
require 'panda/modules/video_state'
|
13
12
|
require 'panda/modules/cloud_connection'
|
14
13
|
require 'panda/proxies/proxy'
|
@@ -17,7 +16,7 @@ require 'panda/proxies/encoding_scope'
|
|
17
16
|
require 'panda/proxies/video_scope'
|
18
17
|
require 'panda/proxies/profile_scope'
|
19
18
|
require 'panda/adapters/adapter'
|
20
|
-
require 'panda/adapters/
|
19
|
+
require 'panda/adapters/faraday'
|
21
20
|
require 'panda/errors'
|
22
21
|
require 'panda/base'
|
23
22
|
require 'panda/resources/resource'
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'faraday'
|
2
|
-
require 'yajl/json_gem'
|
3
2
|
require 'typhoeus'
|
4
3
|
|
5
4
|
module Panda
|
@@ -53,15 +52,16 @@ module Panda
|
|
53
52
|
|
54
53
|
def connection
|
55
54
|
@conn ||= ::Faraday.new(:url => @api_url) do |builder|
|
56
|
-
builder.request
|
55
|
+
builder.request :multipart
|
56
|
+
builder.request :url_encoded
|
57
57
|
builder.adapter :typhoeus
|
58
58
|
end
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
def rescue_json_parsing(&block)
|
62
62
|
begin
|
63
|
-
|
64
|
-
rescue
|
63
|
+
MultiJson.decode(yield)
|
64
|
+
rescue MultiJson::DecodeError => e
|
65
65
|
raise(ServiceNotAvailable)
|
66
66
|
end
|
67
67
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'restclient'
|
2
|
-
require 'json' unless defined?(ActiveSupport::JSON) || defined?(JSON::JSON_LOADED)
|
3
2
|
|
4
3
|
module Panda
|
5
4
|
module Adapter
|
@@ -12,55 +11,43 @@ module Panda
|
|
12
11
|
def get(request_uri, params)
|
13
12
|
rescue_json_parsing do
|
14
13
|
query = ApiAuthentication.hash_to_query(params)
|
15
|
-
|
14
|
+
connection[request_uri + '?' + query].get
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
19
18
|
def post(request_uri, params)
|
20
19
|
rescue_json_parsing do
|
21
|
-
|
20
|
+
connection[request_uri].post(params)
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
25
24
|
def put(request_uri, params)
|
26
25
|
rescue_json_parsing do
|
27
|
-
|
26
|
+
connection[request_uri].put(params)
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
30
|
def delete(request_uri, params)
|
32
31
|
rescue_json_parsing do
|
33
32
|
query = ApiAuthentication.hash_to_query(params)
|
34
|
-
|
33
|
+
connection[request_uri + '?' + query].delete
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
37
|
private
|
39
|
-
|
38
|
+
|
40
39
|
def connection
|
41
40
|
@conn ||= ::RestClient::Resource.new(@api_url)
|
42
41
|
end
|
43
|
-
|
44
|
-
def hash_response(response)
|
45
|
-
begin
|
46
|
-
if defined?(ActiveSupport::JSON)
|
47
|
-
ActiveSupport::JSON.decode(response)
|
48
|
-
else
|
49
|
-
JSON.parse(response)
|
50
|
-
end
|
51
|
-
rescue JSON::ParserError => e
|
52
|
-
raise ServiceNotAvailable.new
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
42
|
+
|
56
43
|
def rescue_json_parsing(&block)
|
57
44
|
begin
|
58
|
-
yield
|
59
|
-
rescue ::
|
60
|
-
|
45
|
+
MultiJson.decode(yield)
|
46
|
+
rescue MultiJson::DecodeError => e
|
47
|
+
raise(ServiceNotAvailable)
|
61
48
|
end
|
62
49
|
end
|
63
|
-
|
50
|
+
|
64
51
|
end
|
65
52
|
end
|
66
53
|
end
|
data/lib/panda/base.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'forwardable'
|
2
|
-
|
3
2
|
module Panda
|
4
3
|
class Base
|
5
4
|
attr_accessor :attributes, :errors
|
@@ -9,8 +8,6 @@ module Panda
|
|
9
8
|
include Panda::Builders
|
10
9
|
include Panda::Finders
|
11
10
|
|
12
|
-
def_delegators :attributes, :to_json
|
13
|
-
|
14
11
|
def initialize(attributes = {})
|
15
12
|
clear_attributes
|
16
13
|
load(attributes)
|
@@ -43,6 +40,15 @@ module Panda
|
|
43
40
|
self
|
44
41
|
end
|
45
42
|
|
43
|
+
def inspect
|
44
|
+
attributes_as_nice_string = self.attributes.map {|k,v| "#{k}: #{v.inspect}"}.compact.join(", ")
|
45
|
+
"#<#{self.class} #{attributes_as_nice_string}>"
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_json(*args)
|
49
|
+
MultiJson.encode(self.attributes)
|
50
|
+
end
|
51
|
+
|
46
52
|
private
|
47
53
|
|
48
54
|
def load_and_reset(response)
|
data/lib/panda/panda.rb
CHANGED
@@ -6,7 +6,7 @@ module Panda
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def non_delegate_methods
|
9
|
-
super + [:status, :profile_id, :profile_name, :video, :page, :per_page]
|
9
|
+
super + [:status, :profile_id, :profile_name, :video, :page, :per_page, :[]]
|
10
10
|
end
|
11
11
|
|
12
12
|
def page(this_page)
|
@@ -44,5 +44,13 @@ module Panda
|
|
44
44
|
trigger_request.first
|
45
45
|
end
|
46
46
|
|
47
|
+
def [](index)
|
48
|
+
if(index.is_a? String)
|
49
|
+
proxy_found.select{|e| e.profile_name == index}[0]
|
50
|
+
else
|
51
|
+
proxy_found[index]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
47
55
|
end
|
48
56
|
end
|
data/lib/panda/proxies/scope.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
module Panda
|
2
2
|
class Encoding < Resource
|
3
3
|
include VideoState
|
4
|
-
|
5
|
-
|
4
|
+
|
6
5
|
belongs_to :video
|
7
6
|
has_one :profile
|
8
7
|
|
@@ -12,7 +11,31 @@ module Panda
|
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
|
-
def
|
14
|
+
def url
|
15
|
+
full_path = "#{path}#{extname}"
|
16
|
+
get_url(full_path) if files.include?(full_path)
|
17
|
+
end
|
16
18
|
|
19
|
+
def urls
|
20
|
+
files.map {|f| "#{cloud.url}#{f}"}
|
21
|
+
end
|
22
|
+
|
23
|
+
def screenshots
|
24
|
+
((1..7).map{|i| get_url("#{path}_#{i}.jpg")} if success?) || []
|
25
|
+
end
|
26
|
+
|
27
|
+
def cancel
|
28
|
+
connection.post("/encodings/#{id}/cancel.json")['canceled']
|
29
|
+
end
|
30
|
+
|
31
|
+
def retry
|
32
|
+
connection.post("/encodings/#{id}/retry.json")['retried']
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def get_url(end_path)
|
38
|
+
"#{cloud.url}#{end_path}"
|
39
|
+
end
|
17
40
|
end
|
18
41
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Panda
|
2
2
|
class Video < Resource
|
3
3
|
include VideoState
|
4
|
-
include Viewable
|
5
4
|
has_many :encodings
|
6
5
|
|
7
6
|
class << self
|
@@ -10,7 +9,23 @@ module Panda
|
|
10
9
|
end
|
11
10
|
end
|
12
11
|
|
13
|
-
def
|
14
|
-
|
12
|
+
def metadata
|
13
|
+
connection.get("/videos/#{id}/metadata.json")
|
14
|
+
end
|
15
|
+
|
16
|
+
def preview_url
|
17
|
+
get_url("#{path}_1.jpg") if success?
|
18
|
+
end
|
19
|
+
|
20
|
+
def url
|
21
|
+
get_url("#{path}#{extname}") if success?
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def get_url(end_path)
|
27
|
+
"#{cloud.url}#{end_path}"
|
28
|
+
end
|
29
|
+
|
15
30
|
end
|
16
31
|
end
|
data/lib/panda/version.rb
CHANGED
data/panda.gemspec
CHANGED
@@ -6,15 +6,16 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = "panda"
|
7
7
|
s.version = Panda::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["
|
9
|
+
s.authors = ["Pandastream"]
|
10
10
|
s.email = ["info@pandastream.com"]
|
11
|
-
s.homepage = "http://github.com/
|
11
|
+
s.homepage = "http://github.com/pandastream/panda_gem"
|
12
12
|
s.summary = %q{Panda Client}
|
13
13
|
s.description = %q{Panda Client}
|
14
14
|
|
15
15
|
s.add_dependency "ruby-hmac", ">= 0.3.2"
|
16
|
-
s.add_dependency "
|
17
|
-
s.add_dependency "
|
16
|
+
s.add_dependency "faraday", ">= 0.7.0"
|
17
|
+
s.add_dependency "typhoeus"
|
18
|
+
s.add_dependency "multi_json"
|
18
19
|
|
19
20
|
s.add_development_dependency "rake"
|
20
21
|
s.add_development_dependency "timecop"
|
data/spec/encoding_spec.rb
CHANGED
@@ -63,11 +63,11 @@ describe Panda::Encoding do
|
|
63
63
|
end
|
64
64
|
|
65
65
|
it "should return the encoding url" do
|
66
|
-
cloud_json = "{\"s3_videos_bucket\":\"my_bucket\",\"id\":\"my_cloud_id\", \"url\":\"http://my_bucket.s3.amazonaws.com/\"}"
|
66
|
+
cloud_json = "{\"s3_videos_bucket\":\"my_bucket\",\"id\":\"my_cloud_id\", \"url\":\"http://my_bucket.s3.amazonaws.com/\"}"
|
67
67
|
stub_http_request(:get, /api.example.com:85\/v2\/clouds\/my_cloud_id.json/).
|
68
68
|
to_return(:body => cloud_json)
|
69
69
|
|
70
|
-
encoding = Panda::Encoding.new({:id => "456", :extname => ".ext", :path => "abc/panda", :status => 'success'})
|
70
|
+
encoding = Panda::Encoding.new({:id => "456", :extname => ".ext", :path => "abc/panda", "files" => ["abc/panda.ext"], :status => 'success'})
|
71
71
|
encoding.url.should == "http://my_bucket.s3.amazonaws.com/abc/panda.ext"
|
72
72
|
end
|
73
73
|
|
data/spec/video_spec.rb
CHANGED
@@ -225,7 +225,12 @@ describe Panda::Video do
|
|
225
225
|
|
226
226
|
it "should return a json on attributes" do
|
227
227
|
video = Panda::Video.new(:attr => "value")
|
228
|
-
|
228
|
+
|
229
|
+
if(RUBY_VERSION >= "1.9")
|
230
|
+
video.to_json.should == "{\"attr\":\"value\",\"cloud_id\":\"my_cloud_id\"}"
|
231
|
+
else
|
232
|
+
video.to_json.should == "{\"cloud_id\":\"my_cloud_id\",\"attr\":\"value\"}"
|
233
|
+
end
|
229
234
|
end
|
230
235
|
|
231
236
|
it "should create an encoding using video scope" do
|
@@ -279,7 +284,7 @@ describe Panda::Video do
|
|
279
284
|
encodings_json = "[{\"abc\":\"my_source_url\",\"id\":\"456\"}]"
|
280
285
|
stub_http_request(:get, /api.example.com:85\/v2\/videos\/123\/encodings.json/).to_return(:body => encodings_json)
|
281
286
|
|
282
|
-
video.encodings.to_json.should == "
|
287
|
+
video.encodings.first.to_json.should == "{\"abc\":\"my_source_url\",\"id\":\"456\",\"cloud_id\":\"my_cloud_id\"}"
|
283
288
|
end
|
284
289
|
|
285
290
|
it "should return the video url" do
|
@@ -297,7 +302,7 @@ describe Panda::Video do
|
|
297
302
|
to_return(:body => cloud_json)
|
298
303
|
|
299
304
|
video = Panda::Video.new({:id => "456", :extname => ".ext", :status => "success", :path => "abc/panda"})
|
300
|
-
video.
|
305
|
+
video.preview_url.should == "http://my_bucket.s3.amazonaws.com/abc/panda_1.jpg"
|
301
306
|
end
|
302
307
|
|
303
308
|
it "should call the request if the scope has changed" do
|
metadata
CHANGED
@@ -1,23 +1,25 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: panda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 5
|
9
|
+
- 0
|
10
|
+
version: 1.5.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
|
-
-
|
13
|
+
- Pandastream
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-10-18 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
+
name: ruby-hmac
|
22
|
+
type: :runtime
|
21
23
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
22
24
|
none: false
|
23
25
|
requirements:
|
@@ -29,11 +31,11 @@ dependencies:
|
|
29
31
|
- 3
|
30
32
|
- 2
|
31
33
|
version: 0.3.2
|
32
|
-
name: ruby-hmac
|
33
|
-
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
requirement: *id001
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
+
name: faraday
|
38
|
+
type: :runtime
|
37
39
|
version_requirements: &id002 !ruby/object:Gem::Requirement
|
38
40
|
none: false
|
39
41
|
requirements:
|
@@ -42,12 +44,14 @@ dependencies:
|
|
42
44
|
hash: 3
|
43
45
|
segments:
|
44
46
|
- 0
|
45
|
-
|
46
|
-
|
47
|
-
|
47
|
+
- 7
|
48
|
+
- 0
|
49
|
+
version: 0.7.0
|
48
50
|
prerelease: false
|
49
51
|
requirement: *id002
|
50
52
|
- !ruby/object:Gem::Dependency
|
53
|
+
name: typhoeus
|
54
|
+
type: :runtime
|
51
55
|
version_requirements: &id003 !ruby/object:Gem::Requirement
|
52
56
|
none: false
|
53
57
|
requirements:
|
@@ -57,11 +61,11 @@ dependencies:
|
|
57
61
|
segments:
|
58
62
|
- 0
|
59
63
|
version: "0"
|
60
|
-
name: json
|
61
|
-
type: :runtime
|
62
64
|
prerelease: false
|
63
65
|
requirement: *id003
|
64
66
|
- !ruby/object:Gem::Dependency
|
67
|
+
name: multi_json
|
68
|
+
type: :runtime
|
65
69
|
version_requirements: &id004 !ruby/object:Gem::Requirement
|
66
70
|
none: false
|
67
71
|
requirements:
|
@@ -71,11 +75,11 @@ dependencies:
|
|
71
75
|
segments:
|
72
76
|
- 0
|
73
77
|
version: "0"
|
74
|
-
name: rake
|
75
|
-
type: :development
|
76
78
|
prerelease: false
|
77
79
|
requirement: *id004
|
78
80
|
- !ruby/object:Gem::Dependency
|
81
|
+
name: rake
|
82
|
+
type: :development
|
79
83
|
version_requirements: &id005 !ruby/object:Gem::Requirement
|
80
84
|
none: false
|
81
85
|
requirements:
|
@@ -85,12 +89,26 @@ dependencies:
|
|
85
89
|
segments:
|
86
90
|
- 0
|
87
91
|
version: "0"
|
88
|
-
name: timecop
|
89
|
-
type: :development
|
90
92
|
prerelease: false
|
91
93
|
requirement: *id005
|
92
94
|
- !ruby/object:Gem::Dependency
|
95
|
+
name: timecop
|
96
|
+
type: :development
|
93
97
|
version_requirements: &id006 !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
version: "0"
|
106
|
+
prerelease: false
|
107
|
+
requirement: *id006
|
108
|
+
- !ruby/object:Gem::Dependency
|
109
|
+
name: rspec
|
110
|
+
type: :development
|
111
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
94
112
|
none: false
|
95
113
|
requirements:
|
96
114
|
- - "="
|
@@ -101,12 +119,12 @@ dependencies:
|
|
101
119
|
- 4
|
102
120
|
- 0
|
103
121
|
version: 2.4.0
|
104
|
-
name: rspec
|
105
|
-
type: :development
|
106
122
|
prerelease: false
|
107
|
-
requirement: *
|
123
|
+
requirement: *id007
|
108
124
|
- !ruby/object:Gem::Dependency
|
109
|
-
|
125
|
+
name: webmock
|
126
|
+
type: :development
|
127
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
110
128
|
none: false
|
111
129
|
requirements:
|
112
130
|
- - ">="
|
@@ -115,10 +133,8 @@ dependencies:
|
|
115
133
|
segments:
|
116
134
|
- 0
|
117
135
|
version: "0"
|
118
|
-
name: webmock
|
119
|
-
type: :development
|
120
136
|
prerelease: false
|
121
|
-
requirement: *
|
137
|
+
requirement: *id008
|
122
138
|
description: Panda Client
|
123
139
|
email:
|
124
140
|
- info@pandastream.com
|
@@ -153,7 +169,6 @@ files:
|
|
153
169
|
- lib/panda/modules/router.rb
|
154
170
|
- lib/panda/modules/updatable.rb
|
155
171
|
- lib/panda/modules/video_state.rb
|
156
|
-
- lib/panda/modules/viewable.rb
|
157
172
|
- lib/panda/panda.rb
|
158
173
|
- lib/panda/proxies/encoding_scope.rb
|
159
174
|
- lib/panda/proxies/profile_scope.rb
|
@@ -174,7 +189,7 @@ files:
|
|
174
189
|
- spec/profile_spec.rb
|
175
190
|
- spec/spec_helper.rb
|
176
191
|
- spec/video_spec.rb
|
177
|
-
homepage: http://github.com/
|
192
|
+
homepage: http://github.com/pandastream/panda_gem
|
178
193
|
licenses: []
|
179
194
|
|
180
195
|
post_install_message:
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Panda
|
2
|
-
module Viewable
|
3
|
-
|
4
|
-
def screenshots
|
5
|
-
((1..screenshots_size||0).map{|i| get_url("_#{i}.jpg")} if success?) || []
|
6
|
-
end
|
7
|
-
|
8
|
-
def url
|
9
|
-
get_url("#{extname}") if success?
|
10
|
-
end
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def get_url(end_path)
|
15
|
-
"#{cloud.url}#{path}#{end_path}"
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
end
|