cloudscrape-client 0.4.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -3
- data/.simplecov +2 -2
- data/CHANGELOG.md +16 -0
- data/Gemfile +2 -0
- data/README.md +32 -3
- data/Rakefile +2 -0
- data/bin/console +1 -1
- data/cloudscrape-client-ruby.gemspec +7 -2
- data/lib/cloudscrape/client.rb +2 -0
- data/lib/cloudscrape_client.rb +3 -0
- data/lib/cloudscrape_client/api.rb +17 -12
- data/lib/cloudscrape_client/configuration.rb +3 -3
- data/lib/cloudscrape_client/dto.rb +10 -1
- data/lib/cloudscrape_client/execution_dto.rb +13 -3
- data/lib/cloudscrape_client/executions.rb +32 -10
- data/lib/cloudscrape_client/executions/get.rb +2 -0
- data/lib/cloudscrape_client/executions/result.rb +9 -1
- data/lib/cloudscrape_client/executions/result/file.rb +68 -0
- data/lib/cloudscrape_client/executions/results.rb +2 -0
- data/lib/cloudscrape_client/run_dto.rb +2 -0
- data/lib/cloudscrape_client/runs.rb +2 -0
- data/lib/cloudscrape_client/validate.rb +4 -2
- data/lib/cloudscrape_client/version.rb +3 -1
- data/postman_collection +413 -170
- metadata +25 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb5efa121917f781a62ec85749da85461bf42d59
|
4
|
+
data.tar.gz: b1720e3a87cbbfc31f59b37cd350ac7372c7c47e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cef617b5a0d055c952e9cc57020654227a46878334afbb57142b1c8ed5e49e6419bff7813d38de9047a940e6b87ff123e5888f3eb4f545ebf011a34738bf6378
|
7
|
+
data.tar.gz: cdb9a6425d8e645d841c8fde5e00437bcfd11302e2ee57ad920a34e213739a5be6a561882659aae2354299702b0a6ac785375a1bae2dc087f0fb18b265b25dee
|
data/.rubocop.yml
CHANGED
data/.simplecov
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
SimpleCov.configure do
|
2
2
|
start("rails") do
|
3
|
-
formatter SimpleCov::Formatter::MultiFormatter[
|
3
|
+
formatter SimpleCov::Formatter::MultiFormatter.new([
|
4
4
|
SimpleCov::Formatter::HTMLFormatter
|
5
|
-
]
|
5
|
+
])
|
6
6
|
|
7
7
|
add_group "Long files" do |src_file|
|
8
8
|
src_file.lines.count > 100
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## 0.5.0 (2016-09-16)
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- Added GetResultFile endpoint support
|
6
|
+
|
7
|
+
Bugfixes:
|
8
|
+
|
9
|
+
- Correctly parse files in response
|
10
|
+
|
11
|
+
## 0.4.0 (2016-05-15)
|
12
|
+
|
13
|
+
Bugfixes:
|
14
|
+
|
15
|
+
- Change Domain to Dexi.io
|
16
|
+
|
1
17
|
## 0.3.0 (2016-03-23)
|
2
18
|
|
3
19
|
Features:
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -7,6 +7,8 @@ Wrapper for CloudScrape API.
|
|
7
7
|
|
8
8
|
## Requirements
|
9
9
|
|
10
|
+
For dependencies see `spec.add_runtime_dependency` in the [Gemspec](./cloudscrape-client-ruby.gemspec)
|
11
|
+
|
10
12
|
* Ruby `> 1.9.x`
|
11
13
|
|
12
14
|
## Installation
|
@@ -102,13 +104,40 @@ client.executions(execution_id).remove
|
|
102
104
|
|
103
105
|
#### Executions (Get Result) [Docs](https://app.dexi.io/#/api/sections/executions/getResult)
|
104
106
|
|
105
|
-
Methods are dynamically defined based on headers.
|
106
|
-
|
107
107
|
``` ruby
|
108
108
|
execution = client.executions(execution_id).results
|
109
109
|
execution.response # => { headers: [...], rows: [...] }
|
110
|
-
execution.collection # => [ #<CloudscrapeClient::Executions::Result:0x007ffd7d132950> ]
|
111
110
|
execution.as_hash # => [ { ... } ]
|
111
|
+
result = execution.collection.first # => #<CloudscrapeClient::Executions::Result:0x007ffd7d132950>
|
112
|
+
|
113
|
+
# Methods are dynamically defined based on headers. For example:
|
114
|
+
result.methods.sort # => [..., :id, :screenshot]
|
115
|
+
|
116
|
+
result.id # => "ae101b8f-1326-451c-ada7-3eab3c0f8a91"
|
117
|
+
|
118
|
+
file = result.screenshot # => #<CloudscrapeClient::Executions::Result::File:0x007ffd7d817161>
|
119
|
+
file.id # => "11fed7f0-a508-4dc8-956a-481535c6f88a"
|
120
|
+
file.content_type # => "image/png"
|
121
|
+
```
|
122
|
+
|
123
|
+
#### Executions (Get Result File) [Docs](https://app.dexi.io/#/api/sections/executions/getResultFile)
|
124
|
+
|
125
|
+
``` ruby
|
126
|
+
execution.collection.first # => #<CloudscrapeClient::Executions::Result:0x007ffd7d132950>
|
127
|
+
result_file = result.screenshot # => #<CloudscrapeClient::Executions::Result::File:0x007ffd7d817161>
|
128
|
+
|
129
|
+
result_file.id # => "11fed7f0-a508-4dc8-956a-481535c6f88a"
|
130
|
+
result_file.provider_id # => 21607
|
131
|
+
result_file.content_type # => "image/png"
|
132
|
+
result_file.file_name # => "<ID>-<PROVIDER_ID>.png"
|
133
|
+
|
134
|
+
# Returns content of file
|
135
|
+
content = client.executions(execution_id).file(result_file) # => "..."
|
136
|
+
|
137
|
+
# Example content usage
|
138
|
+
newFile = File.open(result_file.file_name, "w")
|
139
|
+
newFile.write(content)
|
140
|
+
newFile.close
|
112
141
|
```
|
113
142
|
|
114
143
|
#### Executions (Stop) [Docs](https://app.dexi.io/#/api/sections/executions/stop)
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# coding: utf-8
|
2
4
|
lib = File.expand_path("../lib", __FILE__)
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
6
|
|
5
7
|
require "cloudscrape_client/version"
|
6
8
|
|
9
|
+
# rubocop:disable Metrics/BlockLength
|
7
10
|
Gem::Specification.new do |spec|
|
8
11
|
spec.name = "cloudscrape-client"
|
9
12
|
spec.version = CloudscrapeClient::VERSION
|
@@ -23,16 +26,18 @@ Gem::Specification.new do |spec|
|
|
23
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
27
|
spec.require_paths = ["lib"]
|
25
28
|
|
29
|
+
spec.add_runtime_dependency "mime-types", "~> 3.1"
|
26
30
|
spec.add_runtime_dependency "faraday", "~> 0.9"
|
27
31
|
spec.add_runtime_dependency "faraday_middleware", "~> 0.10"
|
28
32
|
spec.add_runtime_dependency "faraday-conductivity", "~> 0.3"
|
29
33
|
spec.add_runtime_dependency "faraday_middleware-multi_json", "~> 0.0"
|
30
34
|
|
31
|
-
spec.add_development_dependency "bundler"
|
32
|
-
spec.add_development_dependency "rake"
|
35
|
+
spec.add_development_dependency "bundler"
|
36
|
+
spec.add_development_dependency "rake"
|
33
37
|
spec.add_development_dependency "rspec"
|
34
38
|
spec.add_development_dependency "rubocop"
|
35
39
|
spec.add_development_dependency "simplecov"
|
36
40
|
spec.add_development_dependency "vcr"
|
37
41
|
spec.add_development_dependency "webmock"
|
38
42
|
end
|
43
|
+
# rubocop:enable Metrics/BlockLength
|
data/lib/cloudscrape/client.rb
CHANGED
data/lib/cloudscrape_client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "digest"
|
2
4
|
require "faraday"
|
3
5
|
require "faraday_middleware"
|
@@ -21,27 +23,29 @@ class CloudscrapeClient
|
|
21
23
|
new.delete(*args)
|
22
24
|
end
|
23
25
|
|
24
|
-
def get(domain:, url:, options: {})
|
25
|
-
connection(domain
|
26
|
+
def get(domain:, url:, content_type:, options: {})
|
27
|
+
connection(domain: domain, content_type: content_type)
|
28
|
+
.get(URI.escape(url), options)
|
26
29
|
end
|
27
30
|
|
28
|
-
def post(domain:, url:, options: {})
|
29
|
-
connection(domain).post do |req|
|
31
|
+
def post(domain:, url:, content_type:, options: {})
|
32
|
+
connection(domain: domain, content_type: content_type).post do |req|
|
30
33
|
req.url URI.escape(url)
|
31
|
-
req.headers["Content-Type"] =
|
34
|
+
req.headers["Content-Type"] = content_type.to_s
|
32
35
|
req.body = options.to_json
|
33
36
|
end
|
34
37
|
end
|
35
38
|
|
36
|
-
def delete(domain:, url:, options: {})
|
37
|
-
connection(domain
|
39
|
+
def delete(domain:, url:, content_type:, options: {})
|
40
|
+
connection(domain: domain, content_type: content_type)
|
41
|
+
.delete(URI.escape(url), options)
|
38
42
|
end
|
39
43
|
|
40
44
|
private
|
41
45
|
|
42
46
|
def access_key
|
43
|
-
|
44
|
-
|
47
|
+
raise InvalidAccountId, account_id unless account_id
|
48
|
+
raise InvalidApiKey, api_key unless api_key
|
45
49
|
|
46
50
|
Digest::MD5.hexdigest(account_id + api_key)
|
47
51
|
end
|
@@ -60,7 +64,7 @@ class CloudscrapeClient
|
|
60
64
|
|
61
65
|
# rubocop:disable Metrics/AbcSize
|
62
66
|
# rubocop:disable Metrics/MethodLength
|
63
|
-
def connection(domain)
|
67
|
+
def connection(domain:, content_type:)
|
64
68
|
Faraday.new(url: domain) do |faraday|
|
65
69
|
faraday.request :url_encoded
|
66
70
|
|
@@ -72,10 +76,11 @@ class CloudscrapeClient
|
|
72
76
|
accept: "application/json",
|
73
77
|
"X-CloudScrape-Access" => access_key,
|
74
78
|
"X-CloudScrape-Account" => account_id,
|
75
|
-
content_type:
|
79
|
+
content_type: content_type.to_s
|
76
80
|
|
77
81
|
if CloudscrapeClient.configuration.verbose
|
78
|
-
faraday.
|
82
|
+
faraday.use :extended_logging,
|
83
|
+
logger: CloudscrapeClient.configuration.logger
|
79
84
|
end
|
80
85
|
|
81
86
|
faraday.response :multi_json,
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class CloudscrapeClient
|
2
4
|
module Configure
|
3
5
|
def configuration
|
@@ -9,8 +11,6 @@ class CloudscrapeClient
|
|
9
11
|
configuration
|
10
12
|
end
|
11
13
|
|
12
|
-
private
|
13
|
-
|
14
14
|
class Configuration
|
15
15
|
attr_accessor :base_url,
|
16
16
|
:api_key,
|
@@ -21,7 +21,7 @@ class CloudscrapeClient
|
|
21
21
|
:verbose,
|
22
22
|
:logger
|
23
23
|
|
24
|
-
def initialize
|
24
|
+
def initialize
|
25
25
|
self.base_url = base_url_default
|
26
26
|
self.user_agent_app = user_agent_app_default
|
27
27
|
self.user_agent_version = user_agent_version_default
|
@@ -1,8 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "cloudscrape_client/api"
|
2
4
|
require "cloudscrape_client/validate"
|
3
5
|
|
4
6
|
class CloudscrapeClient
|
5
7
|
class DTO
|
8
|
+
DEFAULT_CONTENT_TYPE = MIME::Types["application/json"].first
|
9
|
+
|
6
10
|
attr_reader :options
|
7
11
|
|
8
12
|
def initialize(options:)
|
@@ -30,6 +34,7 @@ class CloudscrapeClient
|
|
30
34
|
method,
|
31
35
|
domain: domain,
|
32
36
|
url: endpoint,
|
37
|
+
content_type: content_type,
|
33
38
|
options: {
|
34
39
|
api_key: api_key,
|
35
40
|
format: "json"
|
@@ -41,8 +46,12 @@ class CloudscrapeClient
|
|
41
46
|
{}
|
42
47
|
end
|
43
48
|
|
49
|
+
def content_type
|
50
|
+
DEFAULT_CONTENT_TYPE
|
51
|
+
end
|
52
|
+
|
44
53
|
def endpoint
|
45
|
-
|
54
|
+
raise NotImplementedError, "Inheriting class must implement"
|
46
55
|
end
|
47
56
|
|
48
57
|
private
|
@@ -1,17 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class CloudscrapeClient
|
2
4
|
class ExecutionDTO < DTO
|
3
5
|
def endpoint
|
4
|
-
"executions
|
6
|
+
["executions", execution_id, url, record_id].compact.join("/")
|
5
7
|
end
|
6
8
|
|
7
9
|
private
|
8
10
|
|
9
|
-
def
|
10
|
-
options
|
11
|
+
def record_id
|
12
|
+
options[:record_id]
|
13
|
+
end
|
14
|
+
|
15
|
+
def execution_id
|
16
|
+
options.fetch(:execution_id)
|
11
17
|
end
|
12
18
|
|
13
19
|
def url
|
14
20
|
options.fetch(:url)
|
15
21
|
end
|
22
|
+
|
23
|
+
def content_type
|
24
|
+
options[:content_type] || super
|
25
|
+
end
|
16
26
|
end
|
17
27
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "cloudscrape_client/execution_dto"
|
2
4
|
require "cloudscrape_client/executions/get"
|
3
5
|
require "cloudscrape_client/executions/result"
|
@@ -10,34 +12,54 @@ class CloudscrapeClient
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def get
|
13
|
-
|
15
|
+
response = dto(
|
16
|
+
url: "",
|
17
|
+
method: :get
|
18
|
+
)
|
19
|
+
|
20
|
+
Get.new(response: response)
|
14
21
|
end
|
15
22
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
23
|
+
def file(result_file)
|
24
|
+
dto(
|
25
|
+
url: "file",
|
26
|
+
method: :get,
|
27
|
+
record_id: result_file.id,
|
28
|
+
content_type: result_file.content_type
|
29
|
+
)
|
19
30
|
end
|
20
31
|
|
21
32
|
def results
|
22
|
-
|
33
|
+
response = dto(
|
34
|
+
url: "result",
|
35
|
+
method: :get
|
36
|
+
)
|
37
|
+
|
38
|
+
Results.new(response: response)
|
23
39
|
end
|
24
40
|
|
25
41
|
def remove
|
26
|
-
dto("", :delete)
|
42
|
+
dto(url: "", method: :delete)
|
27
43
|
end
|
28
44
|
|
29
45
|
def stop
|
30
|
-
dto("stop", :post)
|
46
|
+
dto(url: "stop", method: :post)
|
31
47
|
end
|
32
48
|
|
33
49
|
def continue
|
34
|
-
dto("continue", :post)
|
50
|
+
dto(url: "continue", method: :post)
|
35
51
|
end
|
36
52
|
|
37
53
|
private
|
38
54
|
|
39
|
-
def dto(url,
|
40
|
-
ExecutionDTO.for(
|
55
|
+
def dto(url:, method:, record_id: nil, content_type: nil)
|
56
|
+
ExecutionDTO.for(
|
57
|
+
url: url,
|
58
|
+
method: method,
|
59
|
+
content_type: content_type,
|
60
|
+
execution_id: @id,
|
61
|
+
record_id: record_id
|
62
|
+
)
|
41
63
|
end
|
42
64
|
end
|
43
65
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cloudscrape_client/executions/result/file"
|
4
|
+
|
1
5
|
class CloudscrapeClient
|
2
6
|
class Executions
|
3
7
|
class Result
|
@@ -20,7 +24,11 @@ class CloudscrapeClient
|
|
20
24
|
private
|
21
25
|
|
22
26
|
def define_method_for_header
|
23
|
-
|
27
|
+
lambda do |key, value|
|
28
|
+
self.class.send(:define_method, key) do
|
29
|
+
value.to_s.include?(File::FILE_KEYWORD) ? File.new(value) : value
|
30
|
+
end
|
31
|
+
end
|
24
32
|
end
|
25
33
|
end
|
26
34
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CloudscrapeClient
|
4
|
+
class Executions
|
5
|
+
class Result
|
6
|
+
class File
|
7
|
+
ParseError = Class.new(StandardError)
|
8
|
+
UnknownContentType = Class.new(StandardError)
|
9
|
+
|
10
|
+
FILE_KEYWORD = "FILE"
|
11
|
+
# https://regex101.com/r/zS8xF6/1
|
12
|
+
REGEX = %r{
|
13
|
+
\A # start of line
|
14
|
+
#{FILE_KEYWORD} # detector keywork
|
15
|
+
: # detector vs content split
|
16
|
+
(?'contentType'\w+\/\w+) # content type
|
17
|
+
; # first split
|
18
|
+
(?'providerId'\d+) # Dexi provider id
|
19
|
+
; # second split
|
20
|
+
(?'id'[a-z0-9-]*) # file id
|
21
|
+
\Z # end of line
|
22
|
+
}x
|
23
|
+
EXPECTED_FORMAT = "FILE:<CONTENT_TYPE>;<PROVIDER_ID>;<FILE_ID>"
|
24
|
+
|
25
|
+
def initialize(value)
|
26
|
+
@value = value
|
27
|
+
end
|
28
|
+
|
29
|
+
def id
|
30
|
+
@id ||= find("id")
|
31
|
+
end
|
32
|
+
|
33
|
+
def provider_id
|
34
|
+
@provider_id ||= find("providerId")
|
35
|
+
end
|
36
|
+
|
37
|
+
# ContentType list http://www.freeformatter.com/mime-types-list.html
|
38
|
+
def content_type
|
39
|
+
@content_type ||= MIME::Types[raw_content_type].first.tap do |result|
|
40
|
+
raise UnknownContentType, raw_content_type if result.nil?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def file_name
|
45
|
+
"#{id}-#{provider_id}.#{extension}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def extension
|
49
|
+
content_type.preferred_extension
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
attr_reader :value
|
55
|
+
|
56
|
+
def raw_content_type
|
57
|
+
@raw_content_type ||= find("contentType")
|
58
|
+
end
|
59
|
+
|
60
|
+
def find(key)
|
61
|
+
value.match(REGEX)[key]
|
62
|
+
rescue NoMethodError
|
63
|
+
raise ParseError, "Expected: #{EXPECTED_FORMAT}, Got: #{value}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class CloudscrapeClient
|
2
4
|
class Validate
|
3
5
|
def initialize(response:)
|
@@ -13,8 +15,8 @@ class CloudscrapeClient
|
|
13
15
|
end
|
14
16
|
|
15
17
|
def validate
|
16
|
-
|
17
|
-
|
18
|
+
raise CloudscrapeClient::InternalServerError, message if internal_error?
|
19
|
+
raise CloudscrapeClient::NotFound, message if not_found?
|
18
20
|
|
19
21
|
true
|
20
22
|
end
|
data/postman_collection
CHANGED
@@ -1,180 +1,423 @@
|
|
1
1
|
{
|
2
|
-
"
|
3
|
-
"
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
"variables": [],
|
3
|
+
"info": {
|
4
|
+
"name": "CloudScrape",
|
5
|
+
"_postman_id": "929def16-e7c9-d024-873c-bd0b61ee5c46",
|
6
|
+
"description": "",
|
7
|
+
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
|
8
|
+
},
|
9
|
+
"item": [
|
7
10
|
{
|
8
|
-
"id": "71488e93-9454-db51-8b9c-e15eb0ccfda8",
|
9
11
|
"name": "Executions",
|
10
12
|
"description": "",
|
11
|
-
"
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
"item": [
|
14
|
+
{
|
15
|
+
"name": "Result",
|
16
|
+
"request": {
|
17
|
+
"url": "https://app.cloudscrape.com/api/executions/1f164370-704b-4402-bc15-ba1d00a19d01/result",
|
18
|
+
"method": "GET",
|
19
|
+
"header": [
|
20
|
+
{
|
21
|
+
"key": "X-CloudScrape-Access",
|
22
|
+
"value": "d7818ef991012e3c94e8ea3cda149936",
|
23
|
+
"description": ""
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"key": "X-CloudScrape-Account",
|
27
|
+
"value": "a274a8b2-a664-4acb-959c-9de28644877d",
|
28
|
+
"description": ""
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"key": "Accept",
|
32
|
+
"value": "application/json",
|
33
|
+
"description": ""
|
34
|
+
},
|
35
|
+
{
|
36
|
+
"key": "Content-Type",
|
37
|
+
"value": "application/json",
|
38
|
+
"description": ""
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"key": "User-Agent",
|
42
|
+
"value": "CS-RUBY-CLIENT/1.0",
|
43
|
+
"description": ""
|
44
|
+
},
|
45
|
+
{
|
46
|
+
"key": "Accept-Encoding",
|
47
|
+
"value": "UTF-8",
|
48
|
+
"description": ""
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"key": "Transfer-Encoding",
|
52
|
+
"value": "UTF-8",
|
53
|
+
"description": ""
|
54
|
+
}
|
55
|
+
],
|
56
|
+
"body": {
|
57
|
+
"mode": "formdata",
|
58
|
+
"formdata": []
|
59
|
+
},
|
60
|
+
"description": "Get execution result. As a result can be very large it is advised that you use some method of streaming to parse the result and insert it into your data store of choice.\n\nhttps://app.cloudscrape.com/#/api/sections/executions/getResult"
|
61
|
+
},
|
62
|
+
"response": []
|
63
|
+
},
|
64
|
+
{
|
65
|
+
"name": "Result File",
|
66
|
+
"request": {
|
67
|
+
"url": "https://app.cloudscrape.com/api/executions/1f164370-704b-4402-bc15-ba1d00a19d01/file/11fed7f0-a508-4dc8-956a-481535c6f88a",
|
68
|
+
"method": "GET",
|
69
|
+
"header": [
|
70
|
+
{
|
71
|
+
"key": "X-CloudScrape-Access",
|
72
|
+
"value": "d7818ef991012e3c94e8ea3cda149936",
|
73
|
+
"description": ""
|
74
|
+
},
|
75
|
+
{
|
76
|
+
"key": "X-CloudScrape-Account",
|
77
|
+
"value": "a274a8b2-a664-4acb-959c-9de28644877d",
|
78
|
+
"description": ""
|
79
|
+
},
|
80
|
+
{
|
81
|
+
"key": "Accept",
|
82
|
+
"value": "application/json",
|
83
|
+
"description": ""
|
84
|
+
},
|
85
|
+
{
|
86
|
+
"key": "Content-Type",
|
87
|
+
"value": "application/json",
|
88
|
+
"description": ""
|
89
|
+
},
|
90
|
+
{
|
91
|
+
"key": "User-Agent",
|
92
|
+
"value": "CS-RUBY-CLIENT/1.0",
|
93
|
+
"description": ""
|
94
|
+
},
|
95
|
+
{
|
96
|
+
"key": "Accept-Encoding",
|
97
|
+
"value": "UTF-8",
|
98
|
+
"description": ""
|
99
|
+
},
|
100
|
+
{
|
101
|
+
"key": "Transfer-Encoding",
|
102
|
+
"value": "UTF-8",
|
103
|
+
"description": ""
|
104
|
+
}
|
105
|
+
],
|
106
|
+
"body": {
|
107
|
+
"mode": "formdata",
|
108
|
+
"formdata": []
|
109
|
+
},
|
110
|
+
"description": "Get execution result file contents. Response headers includes the content-type of the file.\n\nhttps://app.cloudscrape.com/#/api/sections/executions/getResultFile"
|
111
|
+
},
|
112
|
+
"response": []
|
113
|
+
},
|
114
|
+
{
|
115
|
+
"name": "Get",
|
116
|
+
"request": {
|
117
|
+
"url": "https://app.cloudscrape.com/api/executions/1f164370-704b-4402-bc15-ba1d00a19d01",
|
118
|
+
"method": "GET",
|
119
|
+
"header": [
|
120
|
+
{
|
121
|
+
"key": "X-CloudScrape-Access",
|
122
|
+
"value": "d7818ef991012e3c94e8ea3cda149936",
|
123
|
+
"description": ""
|
124
|
+
},
|
125
|
+
{
|
126
|
+
"key": "X-CloudScrape-Account",
|
127
|
+
"value": "a274a8b2-a664-4acb-959c-9de28644877d",
|
128
|
+
"description": ""
|
129
|
+
},
|
130
|
+
{
|
131
|
+
"key": "Accept",
|
132
|
+
"value": "application/json",
|
133
|
+
"description": ""
|
134
|
+
},
|
135
|
+
{
|
136
|
+
"key": "Content-Type",
|
137
|
+
"value": "application/json",
|
138
|
+
"description": ""
|
139
|
+
},
|
140
|
+
{
|
141
|
+
"key": "User-Agent",
|
142
|
+
"value": "CS-RUBY-CLIENT/1.0",
|
143
|
+
"description": ""
|
144
|
+
},
|
145
|
+
{
|
146
|
+
"key": "Accept-Encoding",
|
147
|
+
"value": "UTF-8",
|
148
|
+
"description": ""
|
149
|
+
},
|
150
|
+
{
|
151
|
+
"key": "Transfer-Encoding",
|
152
|
+
"value": "UTF-8",
|
153
|
+
"description": ""
|
154
|
+
}
|
155
|
+
],
|
156
|
+
"body": {
|
157
|
+
"mode": "formdata",
|
158
|
+
"formdata": []
|
159
|
+
},
|
160
|
+
"description": "Get execution\n\nhttps://app.cloudscrape.com/#/api/sections/executions/get"
|
161
|
+
},
|
162
|
+
"response": []
|
163
|
+
},
|
164
|
+
{
|
165
|
+
"name": "Stop",
|
166
|
+
"request": {
|
167
|
+
"url": "https://app.cloudscrape.com/api/executions/1f164370-704b-4402-bc15-ba1d00a19d01/stop",
|
168
|
+
"method": "POST",
|
169
|
+
"header": [
|
170
|
+
{
|
171
|
+
"key": "X-CloudScrape-Access",
|
172
|
+
"value": "d7818ef991012e3c94e8ea3cda149936",
|
173
|
+
"description": ""
|
174
|
+
},
|
175
|
+
{
|
176
|
+
"key": "X-CloudScrape-Account",
|
177
|
+
"value": "a274a8b2-a664-4acb-959c-9de28644877d",
|
178
|
+
"description": ""
|
179
|
+
},
|
180
|
+
{
|
181
|
+
"key": "Accept",
|
182
|
+
"value": "application/json",
|
183
|
+
"description": ""
|
184
|
+
},
|
185
|
+
{
|
186
|
+
"key": "Content-Type",
|
187
|
+
"value": "application/json",
|
188
|
+
"description": ""
|
189
|
+
},
|
190
|
+
{
|
191
|
+
"key": "User-Agent",
|
192
|
+
"value": "CS-RUBY-CLIENT/1.0",
|
193
|
+
"description": ""
|
194
|
+
},
|
195
|
+
{
|
196
|
+
"key": "Accept-Encoding",
|
197
|
+
"value": "UTF-8",
|
198
|
+
"description": ""
|
199
|
+
},
|
200
|
+
{
|
201
|
+
"key": "Transfer-Encoding",
|
202
|
+
"value": "UTF-8",
|
203
|
+
"description": ""
|
204
|
+
}
|
205
|
+
],
|
206
|
+
"body": {
|
207
|
+
"mode": "formdata",
|
208
|
+
"formdata": []
|
209
|
+
},
|
210
|
+
"description": "Stop execution. Note that an execution does not stop immediately.\n\nhttps://app.cloudscrape.com/#/api/sections/executions/stop"
|
211
|
+
},
|
212
|
+
"response": []
|
213
|
+
},
|
214
|
+
{
|
215
|
+
"name": "Continue",
|
216
|
+
"request": {
|
217
|
+
"url": "https://app.cloudscrape.com/api/executions/1f164370-704b-4402-bc15-ba1d00a19d01/continue",
|
218
|
+
"method": "POST",
|
219
|
+
"header": [
|
220
|
+
{
|
221
|
+
"key": "X-CloudScrape-Access",
|
222
|
+
"value": "d7818ef991012e3c94e8ea3cda149936",
|
223
|
+
"description": ""
|
224
|
+
},
|
225
|
+
{
|
226
|
+
"key": "X-CloudScrape-Account",
|
227
|
+
"value": "a274a8b2-a664-4acb-959c-9de28644877d",
|
228
|
+
"description": ""
|
229
|
+
},
|
230
|
+
{
|
231
|
+
"key": "Accept",
|
232
|
+
"value": "application/json",
|
233
|
+
"description": ""
|
234
|
+
},
|
235
|
+
{
|
236
|
+
"key": "Content-Type",
|
237
|
+
"value": "application/json",
|
238
|
+
"description": ""
|
239
|
+
},
|
240
|
+
{
|
241
|
+
"key": "User-Agent",
|
242
|
+
"value": "CS-RUBY-CLIENT/1.0",
|
243
|
+
"description": ""
|
244
|
+
},
|
245
|
+
{
|
246
|
+
"key": "Accept-Encoding",
|
247
|
+
"value": "UTF-8",
|
248
|
+
"description": ""
|
249
|
+
},
|
250
|
+
{
|
251
|
+
"key": "Transfer-Encoding",
|
252
|
+
"value": "UTF-8",
|
253
|
+
"description": ""
|
254
|
+
}
|
255
|
+
],
|
256
|
+
"body": {
|
257
|
+
"mode": "formdata",
|
258
|
+
"formdata": []
|
259
|
+
},
|
260
|
+
"description": "Continue a stopped execution. Note that the execution might not start immediately.\n\nhttps://app.cloudscrape.com/#/api/sections/executions/continue"
|
261
|
+
},
|
262
|
+
"response": []
|
263
|
+
},
|
264
|
+
{
|
265
|
+
"name": "Remove",
|
266
|
+
"request": {
|
267
|
+
"url": "https://app.cloudscrape.com/api/executions/1f164370-704b-4402-bc15-ba1d00a19d01",
|
268
|
+
"method": "DELETE",
|
269
|
+
"header": [
|
270
|
+
{
|
271
|
+
"key": "X-CloudScrape-Access",
|
272
|
+
"value": "d7818ef991012e3c94e8ea3cda149936",
|
273
|
+
"description": ""
|
274
|
+
},
|
275
|
+
{
|
276
|
+
"key": "X-CloudScrape-Account",
|
277
|
+
"value": "a274a8b2-a664-4acb-959c-9de28644877d",
|
278
|
+
"description": ""
|
279
|
+
},
|
280
|
+
{
|
281
|
+
"key": "Accept",
|
282
|
+
"value": "application/json",
|
283
|
+
"description": ""
|
284
|
+
},
|
285
|
+
{
|
286
|
+
"key": "Content-Type",
|
287
|
+
"value": "application/json",
|
288
|
+
"description": ""
|
289
|
+
},
|
290
|
+
{
|
291
|
+
"key": "User-Agent",
|
292
|
+
"value": "CS-RUBY-CLIENT/1.0",
|
293
|
+
"description": ""
|
294
|
+
},
|
295
|
+
{
|
296
|
+
"key": "Accept-Encoding",
|
297
|
+
"value": "UTF-8",
|
298
|
+
"description": ""
|
299
|
+
},
|
300
|
+
{
|
301
|
+
"key": "Transfer-Encoding",
|
302
|
+
"value": "UTF-8",
|
303
|
+
"description": ""
|
304
|
+
}
|
305
|
+
],
|
306
|
+
"body": {
|
307
|
+
"mode": "formdata",
|
308
|
+
"formdata": []
|
309
|
+
},
|
310
|
+
"description": "Delete execution permanently\n\nhttps://app.cloudscrape.com/#/api/sections/executions/remove"
|
311
|
+
},
|
312
|
+
"response": []
|
313
|
+
}
|
314
|
+
]
|
19
315
|
},
|
20
316
|
{
|
21
|
-
"id": "1ed33673-dfe5-e160-54d8-c2d1f325cd7e",
|
22
317
|
"name": "Runs",
|
23
318
|
"description": "",
|
24
|
-
"
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
"version": 2,
|
127
|
-
"tests": "",
|
128
|
-
"currentHelper": "normal",
|
129
|
-
"helperAttributes": {},
|
130
|
-
"time": 1444566409009,
|
131
|
-
"name": "Execute with Input",
|
132
|
-
"description": "Starts new execution of run using the input from the body instead of the run itself.\n\nhttps://app.dexi.io/#/api/sections/runs/executeWithInput",
|
133
|
-
"collectionId": "929def16-e7c9-d024-873c-bd0b61ee5c46",
|
134
|
-
"responses": [],
|
135
|
-
"rawModeData": "{\n \"url\": \"http://google.com\"\n}"
|
136
|
-
},
|
137
|
-
{
|
138
|
-
"id": "e505df88-7b71-2e0d-798c-8ed3321aca77",
|
139
|
-
"headers": "X-CloudScrape-Access: d7818ef991012e3c94e8ea3cda149936\nX-CloudScrape-Account: a274a8b2-a664-4acb-959c-9de28644877d\nAccept: application/json\nContent-Type: application/json\nUser-Agent: CS-RUBY-CLIENT/1.0\nAccept-Encoding: UTF-8\nTransfer-Encoding: UTF-8\n",
|
140
|
-
"url": "https://api.dexi.io/runs/27c719bb-f28f-49f5-aedf-dba2f8e60ba3/execute",
|
141
|
-
"pathVariables": {},
|
142
|
-
"preRequestScript": "",
|
143
|
-
"method": "POST",
|
144
|
-
"collectionId": "929def16-e7c9-d024-873c-bd0b61ee5c46",
|
145
|
-
"data": [],
|
146
|
-
"dataMode": "params",
|
147
|
-
"name": "Execute",
|
148
|
-
"description": "Start new execution of run.\n\nhttps://app.dexi.io/#/api/sections/runs/execute",
|
149
|
-
"descriptionFormat": "html",
|
150
|
-
"time": 1444433278119,
|
151
|
-
"version": 2,
|
152
|
-
"responses": [],
|
153
|
-
"tests": "",
|
154
|
-
"currentHelper": "normal",
|
155
|
-
"helperAttributes": {},
|
156
|
-
"folder": "1ed33673-dfe5-e160-54d8-c2d1f325cd7e",
|
157
|
-
"isFromCollection": true
|
158
|
-
},
|
159
|
-
{
|
160
|
-
"id": "fd463224-a926-201f-75db-8ef02b8c257b",
|
161
|
-
"headers": "X-CloudScrape-Access: d7818ef991012e3c94e8ea3cda149936\nX-CloudScrape-Account: a274a8b2-a664-4acb-959c-9de28644877d\nAccept: application/json\nContent-Type: application/json\nUser-Agent: CS-RUBY-CLIENT/1.0\nAccept-Encoding: UTF-8\nTransfer-Encoding: UTF-8\n",
|
162
|
-
"url": "https://api.dexi.io/executions/1f164370-704b-4402-bc15-ba1d00a19d01/result",
|
163
|
-
"preRequestScript": "",
|
164
|
-
"pathVariables": {},
|
165
|
-
"method": "GET",
|
166
|
-
"data": [],
|
167
|
-
"dataMode": "params",
|
168
|
-
"version": 2,
|
169
|
-
"tests": "",
|
170
|
-
"currentHelper": "normal",
|
171
|
-
"helperAttributes": {},
|
172
|
-
"time": 1444436918679,
|
173
|
-
"name": "Result",
|
174
|
-
"description": "Get execution result. As a result can be very large it is advised that you use some method of streaming to parse the result and insert it into your data store of choice.\n\nhttps://app.dexi.io/#/api/sections/executions/getResult",
|
175
|
-
"collectionId": "929def16-e7c9-d024-873c-bd0b61ee5c46",
|
176
|
-
"responses": [],
|
177
|
-
"folder": "71488e93-9454-db51-8b9c-e15eb0ccfda8"
|
319
|
+
"item": [
|
320
|
+
{
|
321
|
+
"name": "Execute",
|
322
|
+
"request": {
|
323
|
+
"url": "https://api.dexi.io/runs/27c719bb-f28f-49f5-aedf-dba2f8e60ba3/execute",
|
324
|
+
"method": "POST",
|
325
|
+
"header": [
|
326
|
+
{
|
327
|
+
"key": "X-CloudScrape-Access",
|
328
|
+
"value": "a343a30529e1f505d4fa48317",
|
329
|
+
"description": ""
|
330
|
+
},
|
331
|
+
{
|
332
|
+
"key": "X-CloudScrape-Account",
|
333
|
+
"value": "a274a8b2-a664-4acb-959c-9de28644877d",
|
334
|
+
"description": ""
|
335
|
+
},
|
336
|
+
{
|
337
|
+
"key": "Accept",
|
338
|
+
"value": "application/json",
|
339
|
+
"description": ""
|
340
|
+
},
|
341
|
+
{
|
342
|
+
"key": "Content-Type",
|
343
|
+
"value": "application/json",
|
344
|
+
"description": ""
|
345
|
+
},
|
346
|
+
{
|
347
|
+
"key": "User-Agent",
|
348
|
+
"value": "CS-RUBY-CLIENT/1.0",
|
349
|
+
"description": ""
|
350
|
+
},
|
351
|
+
{
|
352
|
+
"key": "Accept-Encoding",
|
353
|
+
"value": "UTF-8",
|
354
|
+
"description": ""
|
355
|
+
},
|
356
|
+
{
|
357
|
+
"key": "Transfer-Encoding",
|
358
|
+
"value": "UTF-8",
|
359
|
+
"description": ""
|
360
|
+
}
|
361
|
+
],
|
362
|
+
"body": {
|
363
|
+
"mode": "formdata",
|
364
|
+
"formdata": []
|
365
|
+
},
|
366
|
+
"description": "Start new execution of run.\n\nhttps://app.cloudscrape.com/#/api/sections/runs/execute"
|
367
|
+
},
|
368
|
+
"response": []
|
369
|
+
},
|
370
|
+
{
|
371
|
+
"name": "Execute with Input",
|
372
|
+
"request": {
|
373
|
+
"url": "https://api.dexi.io/runs/bf04bcf8-ada8-4942-be9d-a0ffb4e29173/execute/inputs?connect=true",
|
374
|
+
"method": "POST",
|
375
|
+
"header": [
|
376
|
+
{
|
377
|
+
"key": "X-CloudScrape-Access",
|
378
|
+
"value": "cdd66efb65d9c4aacd397b3b0b5814ca",
|
379
|
+
"description": ""
|
380
|
+
},
|
381
|
+
{
|
382
|
+
"key": "X-CloudScrape-Account",
|
383
|
+
"value": "a274a8b2-a664-4acb-959c-9de28644877d",
|
384
|
+
"description": ""
|
385
|
+
},
|
386
|
+
{
|
387
|
+
"key": "Accept",
|
388
|
+
"value": "application/json",
|
389
|
+
"description": ""
|
390
|
+
},
|
391
|
+
{
|
392
|
+
"key": "Content-Type",
|
393
|
+
"value": "application/json",
|
394
|
+
"description": ""
|
395
|
+
},
|
396
|
+
{
|
397
|
+
"key": "User-Agent",
|
398
|
+
"value": "CS-RUBY-CLIENT/1.0",
|
399
|
+
"description": ""
|
400
|
+
},
|
401
|
+
{
|
402
|
+
"key": "Accept-Encoding",
|
403
|
+
"value": "UTF-8",
|
404
|
+
"description": ""
|
405
|
+
},
|
406
|
+
{
|
407
|
+
"key": "Transfer-Encoding",
|
408
|
+
"value": "UTF-8",
|
409
|
+
"description": ""
|
410
|
+
}
|
411
|
+
],
|
412
|
+
"body": {
|
413
|
+
"mode": "raw",
|
414
|
+
"raw": "{\n \"url\": \"http://www.rightmove.co.uk/property-for-sale/property-53811409.html\"\n}"
|
415
|
+
},
|
416
|
+
"description": "Starts new execution of run using the input from the body instead of the run itself.\n\nhttps://app.cloudscrape.com/#/api/sections/runs/executeWithInput"
|
417
|
+
},
|
418
|
+
"response": []
|
419
|
+
}
|
420
|
+
]
|
178
421
|
}
|
179
422
|
]
|
180
|
-
}
|
423
|
+
}
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudscrape-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles J Hardy
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mime-types
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.1'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: faraday
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,30 +84,30 @@ dependencies:
|
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
|
-
- -
|
87
|
+
- - '>='
|
74
88
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
89
|
+
version: '0'
|
76
90
|
type: :development
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- -
|
94
|
+
- - '>='
|
81
95
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: rake
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
|
-
- -
|
101
|
+
- - '>='
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
103
|
+
version: '0'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
|
-
- -
|
108
|
+
- - '>='
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
110
|
+
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: rspec
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -204,6 +218,7 @@ files:
|
|
204
218
|
- lib/cloudscrape_client/executions.rb
|
205
219
|
- lib/cloudscrape_client/executions/get.rb
|
206
220
|
- lib/cloudscrape_client/executions/result.rb
|
221
|
+
- lib/cloudscrape_client/executions/result/file.rb
|
207
222
|
- lib/cloudscrape_client/executions/results.rb
|
208
223
|
- lib/cloudscrape_client/run_dto.rb
|
209
224
|
- lib/cloudscrape_client/runs.rb
|