link_preview 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +109 -0
- data/Rakefile +15 -0
- data/lib/faraday/follow_redirects.rb +155 -0
- data/lib/link_preview/configuration.rb +86 -0
- data/lib/link_preview/content.rb +350 -0
- data/lib/link_preview/http_client.rb +91 -0
- data/lib/link_preview/http_crawler.rb +114 -0
- data/lib/link_preview/null_crawler.rb +46 -0
- data/lib/link_preview/parser.rb +172 -0
- data/lib/link_preview/spec_helper.rb +1 -0
- data/lib/link_preview/uri.rb +149 -0
- data/lib/link_preview/version.rb +23 -0
- data/lib/link_preview.rb +51 -0
- data/spec/files/requests/bad_utf8.yml +186 -0
- data/spec/files/requests/elasticsearch.yml +2258 -0
- data/spec/files/requests/ggp_png.yml +256 -0
- data/spec/files/requests/kaltura.yml +3612 -0
- data/spec/files/requests/kaltura_opengraph.yml +1266 -0
- data/spec/files/requests/ogp_me.yml +880 -0
- data/spec/files/requests/sliderocket.yml +387 -0
- data/spec/files/requests/support_apple_com.yml +833 -0
- data/spec/files/requests/youtube.yml +3513 -0
- data/spec/files/requests/youtube_404.yml +1055 -0
- data/spec/link_preview/http_crawler_spec.rb +50 -0
- data/spec/link_preview/uri_spec.rb +99 -0
- data/spec/link_preview_spec.rb +383 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/link_preview/link_preview_stubs.rb +26 -0
- metadata +241 -0
@@ -0,0 +1,172 @@
|
|
1
|
+
# Copyright (c) 2014, VMware, Inc. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights to
|
6
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
# of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
# so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require 'multi_json'
|
22
|
+
require 'nokogiri'
|
23
|
+
require 'set'
|
24
|
+
|
25
|
+
module LinkPreview
|
26
|
+
class Parser
|
27
|
+
attr_accessor :discovered_uris
|
28
|
+
|
29
|
+
def initialize(config, options = {})
|
30
|
+
@config = config
|
31
|
+
@options = options
|
32
|
+
self.discovered_uris = Set.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse(data)
|
36
|
+
return {} unless data && data.headers[:content_type] && data.body
|
37
|
+
case data.headers[:content_type]
|
38
|
+
when /image/, 'binary/octet-stream'
|
39
|
+
parse_image(data)
|
40
|
+
when %r{\Atext/html.*}
|
41
|
+
parse_html(data)
|
42
|
+
when %r{\Atext/xml.*}
|
43
|
+
parse_oembed(data)
|
44
|
+
when %r{\Aapplication/json.*}
|
45
|
+
parse_oembed(data)
|
46
|
+
else
|
47
|
+
{}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse_image(data)
|
52
|
+
{
|
53
|
+
:image => {
|
54
|
+
:image_url => data.url,
|
55
|
+
:image_data => parse_image_data(data),
|
56
|
+
:image_content_type => data.headers[:content_type],
|
57
|
+
:image_file_name => parse_image_file_name(data)
|
58
|
+
}
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
# FIXME currently secure_url is favored over url via implicit ordering of keys
|
63
|
+
def parse_html(data)
|
64
|
+
if doc = Nokogiri::HTML.parse(data.body, nil, 'UTF-8')
|
65
|
+
enum_oembed_link(doc) do |link_rel|
|
66
|
+
discovered_uris << LinkPreview::URI.parse(link_rel, @options)
|
67
|
+
end
|
68
|
+
{
|
69
|
+
:opengraph => {
|
70
|
+
:title => find_meta_property(doc, 'og:title'),
|
71
|
+
:description => find_meta_property(doc, 'og:description'),
|
72
|
+
:image_secure_url => find_meta_property(doc, 'og:image:secure_url'),
|
73
|
+
:image => find_meta_property(doc, 'og:image'),
|
74
|
+
:image_url => find_meta_property(doc, 'og:image:url'),
|
75
|
+
:tag => find_meta_property(doc, 'og:tag'),
|
76
|
+
:url => find_meta_property(doc, 'og:url'),
|
77
|
+
:type => find_meta_property(doc, 'og:type'),
|
78
|
+
:site_name => find_meta_property(doc, 'og:site_name'),
|
79
|
+
:video_secure_url => find_meta_property(doc, 'og:video:secure_url'),
|
80
|
+
:video => find_meta_property(doc, 'og:video'),
|
81
|
+
:video_url => find_meta_property(doc, 'og:video:url'),
|
82
|
+
:video_type => find_meta_property(doc, 'og:video:type'),
|
83
|
+
:video_width => find_meta_property(doc, 'og:video:width'),
|
84
|
+
:video_height => find_meta_property(doc, 'og:video:height')
|
85
|
+
},
|
86
|
+
:html => {
|
87
|
+
:title => find_title(doc),
|
88
|
+
:description => find_meta_description(doc),
|
89
|
+
:tags => Array.wrap(find_rel_tags(doc))
|
90
|
+
}
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def parse_oembed(data)
|
96
|
+
oembed_data = case data.headers[:content_type]
|
97
|
+
when /xml/
|
98
|
+
Hash.from_xml(Nokogiri::XML.parse(data.body, nil, 'UTF-8').to_s)['oembed']
|
99
|
+
when /json/
|
100
|
+
MultiJson.load(data.body)
|
101
|
+
end
|
102
|
+
# TODO validate oembed response
|
103
|
+
{ :oembed => (oembed_data || {}).merge(:url => parse_oembed_content_url(data)) }
|
104
|
+
end
|
105
|
+
|
106
|
+
def parse_oembed_content_url(data)
|
107
|
+
if data.url
|
108
|
+
parsed_uri = LinkPreview::URI.parse(data.url, @options)
|
109
|
+
parsed_uri.as_content_uri.to_s
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def parse_image_data(data)
|
114
|
+
StringIO.new(data.body.dup) if data.body
|
115
|
+
end
|
116
|
+
|
117
|
+
def parse_image_file_name(data)
|
118
|
+
if filename = parse_content_disposition_filename(data)
|
119
|
+
filename
|
120
|
+
elsif data.url
|
121
|
+
parsed_uri = LinkPreview::URI.parse(data.url, @options)
|
122
|
+
parsed_uri.path.split('/').last || parsed_uri.hostname.gsub('.', '_')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# see http://www.ietf.org/rfc/rfc1806.txt
|
127
|
+
def parse_content_disposition_filename(data)
|
128
|
+
if data.headers[:'content-disposition'] =~ /filename=(.*?)\z/
|
129
|
+
$1.gsub(/\A['"]+|['"]+\z/, '')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def enum_oembed_link(doc, &block)
|
134
|
+
doc.search("//head/link[@rel='alternate'][@type='application/json+oembed']", "//head/link[@rel='alternate'][@type='text/xml+oembed']").each do |node|
|
135
|
+
next unless node && node.respond_to?(:attributes) && node.attributes['href']
|
136
|
+
yield node.attributes['href'].value
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def find_title(doc)
|
141
|
+
doc.at('head/title').try(:inner_text)
|
142
|
+
end
|
143
|
+
|
144
|
+
# See http://microformats.org/wiki/rel-tag
|
145
|
+
def find_rel_tags(doc)
|
146
|
+
doc.search("//a[@rel='tag']").map(&:inner_text).reject(&:blank?)
|
147
|
+
end
|
148
|
+
|
149
|
+
def enum_meta_pair(doc, key, value)
|
150
|
+
Enumerator.new do |e|
|
151
|
+
doc.search('head/meta').each do |node|
|
152
|
+
next unless node
|
153
|
+
next unless node.respond_to?(:attributes)
|
154
|
+
next unless node.attributes[key]
|
155
|
+
next unless node.attributes[key].value
|
156
|
+
next unless node.attributes[key].value.downcase == value.downcase
|
157
|
+
next unless node.attributes['content']
|
158
|
+
next unless node.attributes['content'].value
|
159
|
+
e.yield node.attributes['content'].value
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def find_meta_description(doc)
|
165
|
+
enum_meta_pair(doc, 'name', 'description').detect(&:present?)
|
166
|
+
end
|
167
|
+
|
168
|
+
def find_meta_property(doc, property)
|
169
|
+
enum_meta_pair(doc, 'property', property).detect(&:present?)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Dir["#{File.dirname(__FILE__)}/../../spec/support/**/*.rb"].each { |f| require f }
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# Copyright (c) 2014, VMware, Inc. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights to
|
6
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
# of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
# so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require 'uri'
|
22
|
+
require 'delegate'
|
23
|
+
require 'oembed'
|
24
|
+
|
25
|
+
require 'addressable/uri'
|
26
|
+
class Addressable::URI
|
27
|
+
alias :normalize_without_encoded_query :normalize
|
28
|
+
# NOTE hack to correctly escape URI query parameters after normalization
|
29
|
+
# see https://github.com/sporkmonger/addressable/issues/50
|
30
|
+
def normalize_with_encoded_query
|
31
|
+
normalize_without_encoded_query.tap do |uri|
|
32
|
+
if uri.query_values.present?
|
33
|
+
uri.query_values = uri.query_values.map { |key, value| [key, value] }
|
34
|
+
end
|
35
|
+
uri
|
36
|
+
end
|
37
|
+
end
|
38
|
+
alias :normalize :normalize_with_encoded_query
|
39
|
+
end
|
40
|
+
|
41
|
+
module LinkPreview
|
42
|
+
class URI < SimpleDelegator
|
43
|
+
def initialize(addressable_uri, options)
|
44
|
+
super addressable_uri
|
45
|
+
@options = options
|
46
|
+
if kaltura_uri?
|
47
|
+
merge_query(kaltura_query)
|
48
|
+
elsif oembed_uri?
|
49
|
+
merge_query(oembed_query)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def normalize
|
54
|
+
super
|
55
|
+
normalize_path
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def as_oembed_uri
|
60
|
+
return self if kaltura_uri? || oembed_uri?
|
61
|
+
register_default_oembed_providers!
|
62
|
+
if provider = OEmbed::Providers.find(self.to_s)
|
63
|
+
self.class.parse(provider.build(self.to_s), @options)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def as_content_uri
|
68
|
+
return self unless kaltura_uri? || oembed_uri?
|
69
|
+
if content_url = self.query_values['url']
|
70
|
+
self.class.parse(content_url, @options)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_absolute(reference_uri)
|
75
|
+
return self if absolute?
|
76
|
+
self.class.parse(::URI.join(reference_uri, self.path), @options)
|
77
|
+
end
|
78
|
+
|
79
|
+
def for_display
|
80
|
+
self.path.sub!(%r{/\z}, '')
|
81
|
+
self.path = nil if self.path.blank?
|
82
|
+
self.query = nil if self.query.blank?
|
83
|
+
self.fragment = nil if self.fragment.blank?
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
class << self
|
88
|
+
def parse(uri, options = {})
|
89
|
+
return unless uri
|
90
|
+
self.new(Addressable::URI.parse(safe_escape(uri)), options).normalize
|
91
|
+
end
|
92
|
+
|
93
|
+
def unescape(uri)
|
94
|
+
Addressable::URI.unescape(uri, Addressable::URI)
|
95
|
+
end
|
96
|
+
|
97
|
+
def escape(uri)
|
98
|
+
Addressable::URI.escape(uri, Addressable::URI)
|
99
|
+
end
|
100
|
+
|
101
|
+
def safe_escape(uri)
|
102
|
+
parsed_uri = Addressable::URI.parse(uri)
|
103
|
+
unescaped = self.unescape(parsed_uri)
|
104
|
+
if unescaped.to_s == parsed_uri.to_s
|
105
|
+
self.escape(parsed_uri)
|
106
|
+
else
|
107
|
+
parsed_uri
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def merge_query(query)
|
115
|
+
self.query_values ||= {}
|
116
|
+
self.query_values = self.query_values.merge(query.stringify_keys).to_a
|
117
|
+
end
|
118
|
+
|
119
|
+
def normalize_path
|
120
|
+
self.path += '/' if self.path.empty?
|
121
|
+
if kaltura_uri?
|
122
|
+
self.path += '/' unless self.path =~ %r{/\z}
|
123
|
+
end
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
127
|
+
def oembed_uri?
|
128
|
+
query_values.present? && path =~ /oembed/i && query_values['url']
|
129
|
+
end
|
130
|
+
|
131
|
+
def kaltura_uri?
|
132
|
+
query_values.present? && query_values['playerId'] && query_values['entryId']
|
133
|
+
end
|
134
|
+
|
135
|
+
def oembed_query
|
136
|
+
{:maxwidth => @options[:width], :maxheight => @options[:height]}.reject { |_,value| value.nil? }
|
137
|
+
end
|
138
|
+
|
139
|
+
def kaltura_query
|
140
|
+
{:width => @options[:width], :height => @options[:height]}.reject { |_,value| value.nil? }
|
141
|
+
end
|
142
|
+
|
143
|
+
def register_default_oembed_providers!
|
144
|
+
return if OEmbed::Providers.urls.any?
|
145
|
+
OEmbed::Providers.register_all
|
146
|
+
OEmbed::Providers.register_fallback(OEmbed::ProviderDiscovery)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Copyright (c) 2014, VMware, Inc. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights to
|
6
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
# of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
# so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
module LinkPreview
|
22
|
+
VERSION = '0.2.7'
|
23
|
+
end
|
data/lib/link_preview.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Copyright (c) 2014, VMware, Inc. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights to
|
6
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
# of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
# so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require 'link_preview/configuration'
|
22
|
+
require 'link_preview/content'
|
23
|
+
|
24
|
+
module LinkPreview
|
25
|
+
class Client
|
26
|
+
def configure
|
27
|
+
yield configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
def configuration
|
31
|
+
@configuration ||= LinkPreview::Configuration.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def fetch(uri, options = {}, sources = {})
|
35
|
+
LinkPreview::Content.new(configuration, uri, options, sources)
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_content(uri, options = {}, sources = {})
|
39
|
+
LinkPreview::Content.new(configuration, uri, options.merge(allow_requests: false), sources)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
extend Forwardable
|
44
|
+
extend self
|
45
|
+
|
46
|
+
def default_client
|
47
|
+
@default_client ||= Client.new
|
48
|
+
end
|
49
|
+
|
50
|
+
def_delegators :default_client, :fetch, :load_content, :configure, :configuration
|
51
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://s.taobao.com/
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
base64_string: ''
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- Faraday v0.9.0
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- ! '*/*'
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: !binary |-
|
20
|
+
T0s=
|
21
|
+
headers:
|
22
|
+
!binary "U2VydmVy":
|
23
|
+
- !binary |-
|
24
|
+
VGVuZ2luZQ==
|
25
|
+
!binary "RGF0ZQ==":
|
26
|
+
- !binary |-
|
27
|
+
TW9uLCAyNCBNYXIgMjAxNCAwMTo1NzoxMSBHTVQ=
|
28
|
+
!binary "Q29udGVudC1UeXBl":
|
29
|
+
- !binary |-
|
30
|
+
dGV4dC9odG1sOyBjaGFyc2V0PUdCSw==
|
31
|
+
!binary "VHJhbnNmZXItRW5jb2Rpbmc=":
|
32
|
+
- !binary |-
|
33
|
+
Y2h1bmtlZA==
|
34
|
+
!binary "Q29ubmVjdGlvbg==":
|
35
|
+
- !binary |-
|
36
|
+
Y2xvc2U=
|
37
|
+
!binary "VmFyeQ==":
|
38
|
+
- !binary |-
|
39
|
+
QWNjZXB0LUVuY29kaW5n
|
40
|
+
!binary "Q29udGVudC1FbmNvZGluZw==":
|
41
|
+
- !binary |-
|
42
|
+
Z3ppcA==
|
43
|
+
body:
|
44
|
+
encoding: ASCII-8BIT
|
45
|
+
base64_string: ! 'H4sIAAAAAAAAA9Va628c1RX/XEv5Hy4TbWQ3nse+HD921vLaDhAlaYXdkoLQ
|
46
|
+
|
47
|
+
6u7M3d2x55WZu16bkH+mPIQg0ESJgRBeBQcc54FJQoJQqyLaQgtqq/QDBbWg
|
48
|
+
|
49
|
+
njuP3dnHrNfBW6mbyDNz77nnnPs7j3vundk3hHIPqJZC12yCqtTQ80O58EKw
|
50
|
+
|
51
|
+
mh9C8MsZhGKkVLHjEipzldIyF3RQjeokf+32ueeufnT1XznRf/b7XMXRbJqv
|
52
|
+
|
53
|
+
FJfdomGZGrWcokuRjA6apI7mMCVTHiH71TVTtepCRVshZmHt8Lx86nRnZ1Gx
|
54
|
+
|
55
|
+
zLJWkU81etgP2/bD6iRKj7a0UsvSS9iZRGWsu6S1r05K9fokok6trQPboKjq
|
56
|
+
|
57
|
+
TqJWCey35FIHK8vEmXwcSYIkSUn0RAvR6aHOu5/kxACEIR+SB3geLaAHj/6s
|
58
|
+
|
59
|
+
MHMUzS4sIJ7P7xvK6Zq5jByiy5xL13TiVgmhHKo6pCxzVUrtSVGsCLSkqKag
|
60
|
+
|
61
|
+
mCItiRXdKmFdTAljghQ88IYGva7LMYZMznybnFbhR0LZvoLIdZRusqanlzXX
|
62
|
+
|
63
|
+
XROXxaSQBlnekydqyR3tociSO03llJRMSxPJcS7fwKFdN1+NqL/EaQLCqOvY
|
64
|
+
|
65
|
+
oBHAL2RFl2KQZimWAcI4GN9wzxot8+Mcagr12e8a5DhxHshDHUwJdpQqh1gg
|
66
|
+
|
67
|
+
yRw4pa4pmGqWKVo2Mf1elfgaQevBVUMHYhYuMhfGT6hOZIjg0YkgLyf6AZkr
|
68
|
+
|
69
|
+
Weoa0lSZg7AgqwBuAJwvmZJVKi7hFey3gqbD5ZqpMJloWB0B117BDqKyKigO
|
70
|
+
|
71
|
+
gRic14lBTDrMBfQjU1Tozgk6sLtmKjILHHhgKtASXyIY4pLHtl5zuakhKoAR
|
72
|
+
|
73
|
+
Zih1tFKNkmGOrNrYwYbLjXKAB6lYzpp8oOYSB4Yf8AeNeKPA7MOeIdxJTgb1
|
74
|
+
|
75
|
+
dMvHT7AdiwLw+nTQK4ouNxmaDHMjB7mm2VzRY1lcSTGvmBpShQqhwRTdwtoi
|
76
|
+
|
77
|
+
rhzHBmjFoORGHpeeEMBSxFRnq5quDlPQ5PTIMKTDGhsAT5EA3glm5g/tUIeJ
|
78
|
+
|
79
|
+
wIMcMl886A1SH32g7cQ/QuMZAog8U0TaNdUb2WGVJkWcdVCnecbTE1JmPHto
|
80
|
+
|
81
|
+
rGmnCB+HyW9YDMlsdh02Q9MoYjU0iSJ2QwdRD8uFknZvQS8Hx1qxJQs+tHjs
|
82
|
+
|
83
|
+
qJeAcqq24sXUkeKCRslxvMIhRceuC4ENz7wJDUEe6aAsqB20fEkNyL0hNb19
|
84
|
+
|
85
|
+
xNFuQ3idZcqa3nPkI11HOtGRORF0hDkFFzbjMP9vvnj921eevf58o2E+Hgob
|
86
|
+
|
87
|
+
V0hDWH0iK7UjwExAnOhEWU8woAIexCtsNfK6Wi5ROlhwazrIYQxdWtKtitUY
|
88
|
+
|
89
|
+
1BzXcuevFiyJR4MxWPtQ249ly1OdzV4XLOgVx6qZoKilW1As7C+Xy1OdxKc7
|
90
|
+
|
91
|
+
m/YHusawti2wDgTCJMIl19Ih1rqwZb8q0SpVCuVLSrJXY2jqmkqrkwgsEEvS
|
92
|
+
|
93
|
+
nMokqjn6cBhmmlGRMkKwdrFAswwRolHUMuJisnbslydOrB0/ceKEUnLVNOFB
|
94
|
+
|
95
|
+
Ag+KCLZZgWDfFQ4IoxgoDOxUNABiLGuvIgn+pccysfNQNdfW8dokAqbKcm88
|
96
|
+
|
97
|
+
UqlsLJ8Q1rF4kqaJYP2GrLXSzURdZiyUsFnhvbUXVbMxkw78qU+O/lLPU1xC
|
98
|
+
|
99
|
+
uobwnvCMaKnFmea+OeqaUNYcKOa1veeM8Oj/HiJISELVot0kt1FBlNVH95ct
|
100
|
+
|
101
|
+
ixInLq9YDuRFflfK7IcldwUGmTWj99xYikIPaIZtORSbNMa5i41AMi2zX8cO
|
102
|
+
|
103
|
+
MMY1ao02nsqWYyBBM+0aHUU7GQaedKJQou6CFAn6rqidXtS+tj0ZeiTeHyiB
|
104
|
+
|
105
|
+
qGXuzC7Wzs31QzNgsdxF6tVPpsdPqOoS5N5fHDGcVT6ZTfKpQ32nXqho2PrX
|
106
|
+
|
107
|
+
tt7lcOt+pl6vBwp40qdd25CTQio5lpmYGBNwKpnJTpSFJOxDIEezrVORWnb7
|
108
|
+
|
109
|
+
IpoTccd67JcW+4b2BUVGg5aVFPvDwgTNH59rbO+a3X7Z0NkZ1GiLBeFBbyMJ
|
110
|
+
|
111
|
+
TqfR4ZGptn2cX9V4t5EyImKwmIIkoChZqxGCGCKojysV4rhtlB41lGQB8bLL
|
112
|
+
|
113
|
+
u3WNwsazpPslYliseVwWcanLeI8HpLCGQN+vOaRiinlfvl/VAIpG0KySMq7p
|
114
|
+
|
115
|
+
lFVkMmd6JRKztQbtUOUCG7YPCHePXP7cc+cuMLPlRF2L16BDoFsF63clZ79O
|
116
|
+
|
117
|
+
RQIvc6M+5vObhppcZuyCXXFvptjbMu2GX8/Zr3/1/rX42bcW2H5Lw6N6uISN
|
118
|
+
|
119
|
+
TaKj4MF17KCh1Qdgy0Vhy9HNbbxUEnWPw8xVUTh3MTw/MAitWkBWYacTMcZj
|
120
|
+
|
121
|
+
YfTx51sf3Lz02jeQH+/+9Y0fvFDqTu3l7qBSBtBUYnLIhD0UO0CACsgrfYoa
|
122
|
+
|
123
|
+
eOAK1mvMDXz4nyympGRKyiaznBjHOgYmvqwRXXU70GprB/sasEf1urhgf/Ll
|
124
|
+
|
125
|
+
xX+/d+nW9jufbbz99Jnb/3zlszdusVl+9N3Wm1jXH2WVX0vW6EMlP83HhGJj
|
126
|
+
|
127
|
+
nE8VDi1Rk2890XFrJUMDy179CLGDTp+8hx6+U/Wlp2cgb9ndSUnflNjRMF/F
|
128
|
+
|
129
|
+
rm3ZNTvw/p7jgp83DkAvWZAEZU7XXHAxx2InUGEr7Pca/Va53BfbZjYMx/Ke
|
130
|
+
|
131
|
+
nmxZKXmFk8xJfXFi4XEydM6TDYfkEJQyCqlaOqwbMvfB11t/2vz65gvsxGx9
|
132
|
+
|
133
|
+
Y+PTzd/3xbwY5K6uDJAOVZ7MPVnlZ49zaJWvk9KyRnnXJkSp9oVtjZ13GLZO
|
134
|
+
|
135
|
+
KOkfOnawF9fVJS21dEO4DMS7AiNgRSGuu0zWwPUjJjHwqk7MCq3K3JjEdZl2
|
136
|
+
|
137
|
+
aLRTp06ePu0viN4p585G3IWF7h+2uNwRMywnsrzdc72IFiTdaxO2g0DNbQQ7
|
138
|
+
|
139
|
+
rPbXXijHOJxKS46QFJIZDnk1ncwZmskHG9gk2/NzrRXUfijSgBQ7tHl23nLw
|
140
|
+
|
141
|
+
YtXDk5pqNp9rlBqawrJgTtTyb97b/PjiJ3d/feXDK9/nRCDyqS29CwDNUsXb
|
142
|
+
|
143
|
+
8UWhz2n5JGPXswZdqgmYeiner0GhRJZ7LPQn5cTcWGJOSszC/8OJ2UxifiYx
|
144
|
+
|
145
|
+
m03MzCfmDiUK0gHXqjkKkQGDoj/kAFaL3lmy4V0U/2J7F4BPSiWT6eTEGMHj
|
146
|
+
|
147
|
+
5XKaHMpEqt0S+NRy4xT+zvY7H258dfnlu2e5fPOeVRIRW3ctKQCjVlhSg4Dl
|
148
|
+
|
149
|
+
kAfIBICQKMwkDo8PEIq7H145+/q3XN6/3hcE6b2HAOqRjOcaqUThcGJ+PlHI
|
150
|
+
|
151
|
+
MCQG7RdM7Pa7b//9wuvMM6JP9wVMZhC+kUnMzHlwZBKzEC/zidmxROHQAEG5
|
152
|
+
|
153
|
+
/dKFC1s33n+Vy4d39wVGdgBgzCYThQnmJzOzfuYYIAy/vbh95vLLXN6/9oAg
|
154
|
+
|
155
|
+
J7LsGh7JR9J11aI7ZOubl+78jmXrzc33Lu82W7dhO5CE/f8YliFYHfgMInP7
|
156
|
+
|
157
|
+
yxfEZQFiFO6zvnMOEJvLL2+9uf7s9hkuH979GEwGkMpZkEJ4zqWY18yOQ8AO
|
158
|
+
|
159
|
+
MkjP3Hx38yIEqXf9MUgMIne3eEeaVTywxs8OMnKYT5zfuPKO7x3s7sdgMpAU
|
160
|
+
|
161
|
+
nk7MFBgUc+OJ2bnEPPgIOMsg17P3Xtz45Prn1+5y+fCun/VMtFpfuXq3LS83
|
162
|
+
|
163
|
+
HRKt3lmGdwGJ/Gv/eeWzs/fWn82J3mM7YjDBloPbsmMZsj/jYrCHaJ9Hi0T2
|
164
|
+
|
165
|
+
1z8CC5cLT3zHyRdMagfRnjTBrtrTZQVTefGR4sKxAzurk9/6/t2vz97rfgx3
|
166
|
+
|
167
|
+
X2IfXexH7I2Na3/eU7EPPfbzfuRe+s3dc++/uqeSjxzpR/AbN9+6tadiDy/0
|
168
|
+
|
169
|
+
I/bVH7Zu7KnYhb5g3jq/xyAf+1U/Yjdeu/XMnop97KF+xJ5ff+r6F2/94anz
|
170
|
+
|
171
|
+
f7nxj27iO7/4CE8HiKk2zwaaJ5HR1ERLvP8Ss/11SZejibR/jtNCH+WlWPaa
|
172
|
+
|
173
|
+
w84rIrwOsMYpxOoytNjAAp39YvP5q9/d2s6VnCbt7W/urK9/uX355vqNe2+9
|
174
|
+
|
175
|
+
dOuF7b+9feXOM0+//vEfCyk+JUnjUiqV6ZpngxMT/90oezUafEjSeJnK5V1J
|
176
|
+
|
177
|
+
Gkulk4JijLV8GBPFLVKW+0f0x63ig5b3Mizsi76Danzl5WBTHY5+6OUQWnNM
|
178
|
+
|
179
|
+
ZLNPER826fAxTKsCo7IMoPspSkrshw6iZPihUuTjpJYvIMUlV2SfnBKnppPG
|
180
|
+
|
181
|
+
95QZKZnMRr6nhNHsAxd29b/a/S+k7EWd0CsAAA==
|
182
|
+
|
183
|
+
'
|
184
|
+
http_version:
|
185
|
+
recorded_at: Mon, 24 Mar 2014 01:57:12 GMT
|
186
|
+
recorded_with: VCR 2.8.0
|