reddit_bot 1.4.0 → 1.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +2 -1
- data/examples/.bashrc +2 -0
- data/examples/Gemfile +7 -0
- data/examples/Gemfile.lock +35 -0
- data/examples/devflairbot/main.rb +1 -1
- data/examples/get_dimensions.rb +192 -0
- data/examples/largeimages/Gemfile +9 -2
- data/examples/largeimages/Gemfile.lock +82 -7
- data/examples/largeimages/main.rb +63 -112
- data/examples/mlgtv/channels.txt +2 -0
- data/examples/mlgtv/main.rb +1 -0
- data/examples/realtimeww2/main.rb +31 -18
- data/lib/reddit_bot.rb +14 -14
- data/lib/reddit_bot/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b7de090239a739e1cce2756333780cd2d8ce89f
|
4
|
+
data.tar.gz: 3bafbb4a30453016dc61bfd524c671453e8637e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a37ddd7ff716714fc355679374d24893e11c0f2e0286fbdaa89ef763aafdc98ea00d7d009556bb1ed06d46ce3fea6cec2ebf6dd63c2a7569ec8c21a7813c3949
|
7
|
+
data.tar.gz: 7ec222f131e2c77692d0b78f6f37304d250c1d716e21b57564f3b24334185cd4b41dbc94c62c3ea15db4843ce1982d2c699a9de8cf1ecc6647fe66018a860e06
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -78,7 +78,8 @@ or via Gemfile:
|
|
78
78
|
gem "reddit_bot"
|
79
79
|
|
80
80
|
TODO: write more usage instructions here
|
81
|
-
TODO: manual on how to create bots with Reddit web interface and run via bash console
|
81
|
+
TODO: manual on how to create bots with Reddit web interface and run via bash console
|
82
|
+
TODO: about NetHTTPUtils dependency; and that get_rersponse returns String code not Integer like request_data
|
82
83
|
|
83
84
|
To update the gem version in Gemfile.lock when using Gemfile like this: `gem "reddit_bot", "~>1.1.0"`, do the:
|
84
85
|
|
data/examples/.bashrc
ADDED
data/examples/Gemfile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git@github.com:Nakilon/imgur2array.git
|
3
|
+
revision: 70d91ea57bcc5c366fe9407d1e45536ed45e2395
|
4
|
+
tag: v0.0.2.1
|
5
|
+
specs:
|
6
|
+
imgur2array (0.0.2.1)
|
7
|
+
|
8
|
+
GIT
|
9
|
+
remote: git@github.com:Nakilon/nethttputils.git
|
10
|
+
revision: 0c5e79842b8e89c12de4f44b2b41aef3e4614216
|
11
|
+
tag: v0.0.2.0
|
12
|
+
specs:
|
13
|
+
nethttputils (0.0.2.0)
|
14
|
+
|
15
|
+
GEM
|
16
|
+
remote: https://rubygems.org/
|
17
|
+
specs:
|
18
|
+
addressable (2.5.2)
|
19
|
+
public_suffix (>= 2.0.2, < 4.0)
|
20
|
+
fastimage (1.7.0)
|
21
|
+
addressable (~> 2.3, >= 2.3.5)
|
22
|
+
json (2.1.0)
|
23
|
+
public_suffix (2.0.5)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
fastimage (= 1.7.0)
|
30
|
+
imgur2array!
|
31
|
+
json
|
32
|
+
nethttputils!
|
33
|
+
|
34
|
+
BUNDLED WITH
|
35
|
+
1.16.0
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# TODO maybe activate raise_on_failure optional FastImage param
|
2
|
+
|
3
|
+
require "pp"
|
4
|
+
# require "json"
|
5
|
+
# require "nethttputils"
|
6
|
+
require "imgur2array"
|
7
|
+
require "fastimage"
|
8
|
+
|
9
|
+
module GetDimensions
|
10
|
+
class Error404 < RuntimeError
|
11
|
+
def initialize url
|
12
|
+
# Module.nesting[1].logger.error url
|
13
|
+
super "GetDimensions NotFound error for #{url}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
class ErrorUnknown < RuntimeError
|
17
|
+
def initialize url
|
18
|
+
# Module.nesting[1].logger.error url
|
19
|
+
super "GetDimensions UnknownURL error for #{url}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.get_dimensions url
|
24
|
+
fail "env var missing -- IMGUR_CLIENT_ID" unless ENV["IMGUR_CLIENT_ID"]
|
25
|
+
fail "env var missing -- FLICKR_API_KEY" unless ENV["FLICKR_API_KEY"]
|
26
|
+
fail "env var missing -- _500PX_CONSUMER_KEY" unless ENV["_500PX_CONSUMER_KEY"]
|
27
|
+
|
28
|
+
return :skipped if [
|
29
|
+
%r{^https://www\.youtube\.com/},
|
30
|
+
%r{^http://gfycat\.com/},
|
31
|
+
%r{^https?://(i\.)?imgur\.com/.+\.gifv$}, # TODO: o'rly?!
|
32
|
+
%r{^https?://www\.reddit\.com/},
|
33
|
+
%r{^http://vimeo\.com/},
|
34
|
+
].any?{ |r| r =~ url }
|
35
|
+
return :skipped if %w{ minus com } == begin
|
36
|
+
URI url
|
37
|
+
rescue URI::InvalidURIError
|
38
|
+
return :skipped
|
39
|
+
end.host.split(?.).last(2)
|
40
|
+
fi = lambda do |url|
|
41
|
+
_ = FastImage.size url
|
42
|
+
_ ? [*_, url] : fail
|
43
|
+
end
|
44
|
+
[
|
45
|
+
->_{
|
46
|
+
_ = FastImage.size url
|
47
|
+
[*_, url] if _
|
48
|
+
},
|
49
|
+
->_{ if %w{ imgur com } == URI(_).host.split(?.).last(2)
|
50
|
+
dimensions = Imgur::imgur_to_array _
|
51
|
+
[
|
52
|
+
*dimensions.max_by{ |u, x, y, t| x * y }.take(3).rotate(1),
|
53
|
+
*dimensions.map(&:first),
|
54
|
+
]
|
55
|
+
end },
|
56
|
+
->_{ if %r{^https://www\.flickr\.com/photos/[^/]+/(?<id>[^/]+)} =~ _ ||
|
57
|
+
%r{^https://flic\.kr/p/(?<id>[^/]+)$} =~ _
|
58
|
+
json = JSON.parse NetHTTPUtils.request_data "https://api.flickr.com/services/rest/", form: {
|
59
|
+
method: "flickr.photos.getSizes",
|
60
|
+
api_key: ENV["FLICKR_API_KEY"],
|
61
|
+
photo_id: id,
|
62
|
+
format: "json",
|
63
|
+
nojsoncallback: 1,
|
64
|
+
}
|
65
|
+
raise Error404.new _ if json == {"stat"=>"fail", "code"=>1, "message"=>"Photo not found"}
|
66
|
+
if json["stat"] != "ok"
|
67
|
+
fail [json, _].inspect
|
68
|
+
else
|
69
|
+
json["sizes"]["size"].map do |_|
|
70
|
+
x, y, u = _.values_at("width", "height", "source")
|
71
|
+
[x.to_i, y.to_i, u]
|
72
|
+
end.max_by{ |x, y, u| x * y }
|
73
|
+
end
|
74
|
+
end },
|
75
|
+
->_{ if %r{https?://[^.]+.wiki[mp]edia\.org/wiki(/[^/]+)*/(?<id>File:.+)} =~ _
|
76
|
+
_ = JSON.parse NetHTTPUtils.request_data "https://commons.wikimedia.org/w/api.php", form: {
|
77
|
+
format: "json",
|
78
|
+
action: "query",
|
79
|
+
prop: "imageinfo",
|
80
|
+
iiprop: "url",
|
81
|
+
titles: id,
|
82
|
+
}
|
83
|
+
fi[_["query"]["pages"].values.first["imageinfo"].first["url"]]
|
84
|
+
end },
|
85
|
+
->_{ if %r{^https://500px\.com/photo/(?<id>[^/]+)/[^/]+$} =~ _
|
86
|
+
(JSON.parse NetHTTPUtils.request_data "https://api.500px.com/v1/photos/#{id}", form: {
|
87
|
+
image_size: 2048,
|
88
|
+
consumer_key: ENV["_500PX_CONSUMER_KEY"],
|
89
|
+
} )["photo"].values_at("width", "height", "image_url")
|
90
|
+
end },
|
91
|
+
->_{ raise Error404.new _ if "404" == NetHTTPUtils.get_response(_).code },
|
92
|
+
->_{ raise ErrorUnknown.new _ },
|
93
|
+
].lazy.map{ |_| _[url] }.find{ |_| _ }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
if $0 == __FILE__
|
98
|
+
STDOUT.sync = true
|
99
|
+
puts "self testing..."
|
100
|
+
|
101
|
+
[
|
102
|
+
["http://minus.com/lkP3hgRJd9npi", :skipped],
|
103
|
+
["http://example.com", GetDimensions::ErrorUnknown],
|
104
|
+
["http://i.imgur.com/7xcxxkR.gifv", :skipped],
|
105
|
+
["http://imgur.com/HQHBBBD", [1024, 768, "https://i.imgur.com/HQHBBBD.jpg",
|
106
|
+
"https://i.imgur.com/HQHBBBD.jpg"]],
|
107
|
+
["http://imgur.com/a/AdJUK", [1456, 2592, "https://i.imgur.com/Yunpxnx.jpg",
|
108
|
+
"https://i.imgur.com/Yunpxnx.jpg",
|
109
|
+
"https://i.imgur.com/3afw2aF.jpg",
|
110
|
+
"https://i.imgur.com/2epn2nT.jpg"]],
|
111
|
+
# TODO maybe we should do smth else with video -- maybe raise?
|
112
|
+
["https://imgur.com/9yaMdJq", [720, 404, "https://i.imgur.com/9yaMdJq.mp4",
|
113
|
+
"https://i.imgur.com/9yaMdJq.mp4"]],
|
114
|
+
["http://imgur.com/gallery/dCQprEq/new", [5760, 3840, "https://i.imgur.com/dCQprEq.jpg",
|
115
|
+
"https://i.imgur.com/dCQprEq.jpg"]],
|
116
|
+
["https://www.flickr.com/photos/tomas-/17220613278/", GetDimensions::Error404],
|
117
|
+
["https://www.flickr.com/photos/16936123@N07/18835195572", GetDimensions::Error404],
|
118
|
+
["https://www.flickr.com/photos/44133687@N00/17380073505/", [3000, 2000, "https://farm8.staticflickr.com/7757/17380073505_ed5178cc6a_o.jpg"]], # trailing slash
|
119
|
+
["https://www.flickr.com/photos/jacob_schmidt/18414267018/in/album-72157654235845651/", GetDimensions::Error404], # username in-album
|
120
|
+
["https://www.flickr.com/photos/tommygi/5291099420/in/dateposted-public/", [1600, 1062, "https://farm6.staticflickr.com/5249/5291099420_3bf8f43326_o.jpg"]], # username in-public
|
121
|
+
["https://www.flickr.com/photos/132249412@N02/18593786659/in/album-72157654521569061/", GetDimensions::Error404],
|
122
|
+
["https://www.flickr.com/photos/130019700@N03/18848891351/in/dateposted-public/", [4621, 3081, "https://farm4.staticflickr.com/3796/18848891351_f751b35aeb_o.jpg"]], # userid in-public
|
123
|
+
["https://www.flickr.com/photos/frank3/3778768209/in/photolist-6KVb92-eCDTCr-ur8K-7qbL5z-c71afh-c6YvXW-7mHG2L-c71ak9-c71aTq-c71azf-c71aq5-ur8Q-6F6YkR-eCDZsD-eCEakg-eCE6DK-4ymYku-7ubEt-51rUuc-buujQE-ur8x-9fuNu7-6uVeiK-qrmcC6-ur8D-eCEbei-eCDY9P-eCEhCk-eCE5a2-eCH457-eCHrcq-eCEdZ4-eCH6Sd-c71b5o-c71auE-eCHa8m-eCDSbz-eCH1dC-eCEg3v-7JZ4rh-9KwxYL-6KV9yR-9tUSbU-p4UKp7-eCHfwS-6KVbAH-5FrdbP-eeQ39v-eeQ1UR-4jHAGN", [1024, 681, "https://farm3.staticflickr.com/2499/3778768209_280f82abab_b.jpg"]],
|
124
|
+
["https://www.flickr.com/photos/patricksloan/18230541413/sizes/l", [2048, 491, "https://farm6.staticflickr.com/5572/18230541413_fec4783d79_k.jpg"]],
|
125
|
+
["https://flic.kr/p/vPvCWJ", [2048, 1365, "https://farm1.staticflickr.com/507/19572004110_d44d1b4ead_k.jpg"]],
|
126
|
+
["https://en.wikipedia.org/wiki/Prostitution_by_country#/media/File:Prostitution_laws_of_the_world.PNG", [1427, 628, "https://upload.wikimedia.org/wikipedia/commons/e/e8/Prostitution_laws_of_the_world.PNG"]],
|
127
|
+
["http://commons.wikimedia.org/wiki/File:Eduard_Bohlen_anagoria.jpg", [4367, 2928, "https://upload.wikimedia.org/wikipedia/commons/0/0d/Eduard_Bohlen_anagoria.jpg"]],
|
128
|
+
["https://500px.com/photo/112134597/milky-way-by-tom-hall", [4928, 2888, "https://drscdn.500px.org/photo/112134597/m%3D2048_k%3D1_a%3D1/v2?client_application_id=18857&webp=true&sig=c0d31cf9395d7849fbcce612ca9909225ec16fd293a7f460ea15d9e6a6c34257"]],
|
129
|
+
["https://i.redd.it/si758zk7r5xz.jpg", GetDimensions::Error404],
|
130
|
+
].each do |input, expectation|
|
131
|
+
puts "testing #{input}"
|
132
|
+
if expectation.is_a? Class
|
133
|
+
begin
|
134
|
+
GetDimensions::get_dimensions input
|
135
|
+
fail
|
136
|
+
rescue expectation
|
137
|
+
end
|
138
|
+
else
|
139
|
+
abort "unable to inspect #{input}" unless result = GetDimensions::get_dimensions(input)
|
140
|
+
abort "#{input} :: #{result.inspect} != #{expectation.inspect}" if result != expectation
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
puts "OK #{__FILE__}"
|
145
|
+
exit
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
__END__
|
154
|
+
|
155
|
+
["http://discobleach.com/wp-content/uploads/2015/06/spy-comic.png", []],
|
156
|
+
["http://spaceweathergallery.com/indiv_upload.php?upload_id=113462", []],
|
157
|
+
["http://livelymorgue.tumblr.com/post/121189724125/may-27-1956-in-an-eighth-floor-loft-of-an#notes", [0, 0]],
|
158
|
+
http://mobi900.deviantart.com/art/Sea-Sunrise-Wallpaper-545266270
|
159
|
+
http://mobi900.deviantart.com/art/Sunrise-Field-Wallpaper-545126742
|
160
|
+
|
161
|
+
|
162
|
+
http://boxtail.deviantart.com/art/Celtic-Water-Orbs-548986856 from http://redd.it/3en92j
|
163
|
+
http://imgur.com/OXCVSj7&k82U3Qj#0 from http://redd.it/3ee7j1
|
164
|
+
|
165
|
+
unable to size http://hubblesite.org/newscenter/archive/releases/2015/02/image/a/format/zoom/ from http://redd.it/2rhm8w
|
166
|
+
unable to size http://www.deviantart.com/art/Tree-swing-437944764 from http://redd.it/3fnia2
|
167
|
+
|
168
|
+
unable to size http://imgur.com/gallery/AsJ3N7x/new from http://redd.it/3fmzdg
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
found this to be already submitted
|
175
|
+
[4559, 2727] got from 3foerr: 'https://upload.wikimedia.org/wikipedia/commons/4/47/2009-09-19-helsinki-by-RalfR-062.jpg'
|
176
|
+
retry download 'https://www.reddit.com/r/LargeImages/search.json?q=url%3Ahttps%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2F4%2F47%2F2009-09-19-helsinki-by-RalfR-062.jpg&restrict_sr=on' in 1 seconds because of 503 Service Unavailable
|
177
|
+
|
178
|
+
unable to size http://www.flickr.com/photos/dmacs_photos/12027867364/ from http://redd.it/1vqlgk
|
179
|
+
unable to size https://dl.dropboxusercontent.com/u/52357713/16k.png from http://redd.it/1vomwy
|
180
|
+
|
181
|
+
unable to size http://www.flickr.com/photos/dmacs_photos/12027867364/ from http://redd.it/1vqlgk
|
182
|
+
unable to size https://dl.dropboxusercontent.com/u/52357713/16k.png from http://redd.it/1vomwy
|
183
|
+
|
184
|
+
unable http://imgur.com/r/wallpaper/rZ37ZYN from http://redd.it/3knh3g
|
185
|
+
|
186
|
+
unable http://www.flickr.com/photos/dmacs_photos/12027867364/ from http://redd.it/1vqlgk
|
187
|
+
|
188
|
+
|
189
|
+
unable http://imgur.com/gallery/jm0OKQM from http://redd.it/3ukg4t
|
190
|
+
unable http://imgur.com/gallery/oZXfZ from http://redd.it/3ulz2i
|
191
|
+
|
192
|
+
|
@@ -1,5 +1,12 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
+
gem "json"
|
4
|
+
|
5
|
+
gem "nethttputils", git: "git@github.com:Nakilon/nethttputils.git", tag: "v0.0.2.0"
|
6
|
+
gem "reddit_bot", "~>1.4.0"
|
7
|
+
gem "nokogiri"
|
8
|
+
|
9
|
+
gem "imgur2array", git: "git@github.com:Nakilon/imgur2array.git", tag: "v0.0.2.1"
|
3
10
|
gem "fastimage", "1.7.0"
|
4
|
-
|
5
|
-
gem "
|
11
|
+
|
12
|
+
gem "gcplogger", git: "git@github.com:Nakilon/gcplogger.git", tag: "v0.0.1.1"
|
@@ -1,26 +1,101 @@
|
|
1
1
|
GIT
|
2
|
-
remote:
|
3
|
-
revision:
|
2
|
+
remote: git@github.com:Nakilon/gcplogger.git
|
3
|
+
revision: 42483192d94dd0b3ee13809ef516718daf0f9b05
|
4
|
+
tag: v0.0.1.1
|
4
5
|
specs:
|
5
|
-
|
6
|
+
gcplogger (0.0.1.1)
|
7
|
+
google-cloud-logging
|
8
|
+
|
9
|
+
GIT
|
10
|
+
remote: git@github.com:Nakilon/imgur2array.git
|
11
|
+
revision: 70d91ea57bcc5c366fe9407d1e45536ed45e2395
|
12
|
+
tag: v0.0.2.1
|
13
|
+
specs:
|
14
|
+
imgur2array (0.0.2.1)
|
15
|
+
|
16
|
+
GIT
|
17
|
+
remote: git@github.com:Nakilon/nethttputils.git
|
18
|
+
revision: 0c5e79842b8e89c12de4f44b2b41aef3e4614216
|
19
|
+
tag: v0.0.2.0
|
20
|
+
specs:
|
21
|
+
nethttputils (0.0.2.0)
|
6
22
|
|
7
23
|
GEM
|
8
24
|
remote: https://rubygems.org/
|
9
25
|
specs:
|
10
26
|
addressable (2.3.6)
|
27
|
+
faraday (0.13.1)
|
28
|
+
multipart-post (>= 1.2, < 3)
|
11
29
|
fastimage (1.7.0)
|
12
30
|
addressable (~> 2.3, >= 2.3.5)
|
31
|
+
google-cloud-core (1.0.0)
|
32
|
+
google-cloud-env (~> 1.0)
|
33
|
+
googleauth (~> 0.5.1)
|
34
|
+
google-cloud-env (1.0.1)
|
35
|
+
faraday (~> 0.11)
|
36
|
+
google-cloud-logging (1.2.3)
|
37
|
+
google-cloud-core (~> 1.0)
|
38
|
+
google-gax (~> 0.8.0)
|
39
|
+
stackdriver-core (~> 1.2)
|
40
|
+
google-gax (0.8.12)
|
41
|
+
google-protobuf (~> 3.2)
|
42
|
+
googleapis-common-protos (~> 1.3.5)
|
43
|
+
googleauth (~> 0.5.1)
|
44
|
+
grpc (~> 1.6.6)
|
45
|
+
rly (~> 0.2.3)
|
46
|
+
google-protobuf (3.4.1.1)
|
47
|
+
googleapis-common-protos (1.3.7)
|
48
|
+
google-protobuf (~> 3.0)
|
49
|
+
googleapis-common-protos-types (~> 1.0)
|
50
|
+
grpc (~> 1.0)
|
51
|
+
googleapis-common-protos-types (1.0.1)
|
52
|
+
google-protobuf (~> 3.0)
|
53
|
+
googleauth (0.5.3)
|
54
|
+
faraday (~> 0.12)
|
55
|
+
jwt (~> 1.4)
|
56
|
+
logging (~> 2.0)
|
57
|
+
memoist (~> 0.12)
|
58
|
+
multi_json (~> 1.11)
|
59
|
+
os (~> 0.9)
|
60
|
+
signet (~> 0.7)
|
61
|
+
grpc (1.6.7)
|
62
|
+
google-protobuf (~> 3.1)
|
63
|
+
googleapis-common-protos-types (~> 1.0.0)
|
64
|
+
googleauth (~> 0.5.1)
|
13
65
|
json (2.1.0)
|
14
|
-
|
66
|
+
jwt (1.5.6)
|
67
|
+
little-plugger (1.1.4)
|
68
|
+
logging (2.2.2)
|
69
|
+
little-plugger (~> 1.1)
|
70
|
+
multi_json (~> 1.10)
|
71
|
+
memoist (0.16.0)
|
72
|
+
mini_portile2 (2.1.0)
|
73
|
+
multi_json (1.12.2)
|
74
|
+
multipart-post (2.0.0)
|
75
|
+
nokogiri (1.6.8.1)
|
76
|
+
mini_portile2 (~> 2.1.0)
|
77
|
+
os (0.9.6)
|
78
|
+
reddit_bot (1.4.0)
|
15
79
|
json
|
80
|
+
rly (0.2.3)
|
81
|
+
signet (0.8.1)
|
82
|
+
addressable (~> 2.3)
|
83
|
+
faraday (~> 0.9)
|
84
|
+
jwt (>= 1.5, < 3.0)
|
85
|
+
multi_json (~> 1.10)
|
86
|
+
stackdriver-core (1.2.0)
|
16
87
|
|
17
88
|
PLATFORMS
|
18
89
|
ruby
|
19
90
|
|
20
91
|
DEPENDENCIES
|
21
92
|
fastimage (= 1.7.0)
|
22
|
-
|
23
|
-
|
93
|
+
gcplogger!
|
94
|
+
imgur2array!
|
95
|
+
json
|
96
|
+
nethttputils!
|
97
|
+
nokogiri
|
98
|
+
reddit_bot (~> 1.4.0)
|
24
99
|
|
25
100
|
BUNDLED WITH
|
26
|
-
1.
|
101
|
+
1.16.0
|
@@ -1,88 +1,19 @@
|
|
1
|
-
### THIS
|
2
|
-
### DON'T TRY TO LEARN FROM THIS CODE
|
1
|
+
### THIS WAS MY THE VERY FIRST REDDIT BOT
|
3
2
|
|
4
|
-
if Gem::Platform.local.os == "darwin"
|
5
|
-
require_relative "../../../tcpsm/lib/tcp_socket_measurer"
|
6
|
-
else
|
7
|
-
require_relative "#{Dir.home}/tcp_socket_measurer"
|
8
|
-
end
|
9
|
-
|
10
|
-
%w{
|
11
|
-
198.41.208.137
|
12
|
-
198.41.208.138
|
13
|
-
198.41.208.139
|
14
|
-
198.41.208.140
|
15
|
-
198.41.208.141
|
16
|
-
198.41.208.142
|
17
|
-
198.41.208.143
|
18
|
-
198.41.209.136
|
19
|
-
198.41.209.137
|
20
|
-
198.41.209.138
|
21
|
-
198.41.209.139
|
22
|
-
198.41.209.140
|
23
|
-
198.41.209.141
|
24
|
-
198.41.209.142
|
25
|
-
198.41.209.143
|
26
|
-
|
27
|
-
151.101.33.140
|
28
|
-
151.101.32.193
|
29
|
-
}.each do |ip|
|
30
|
-
TCPSocketMeasurer.known_hosts[ip] = "www.reddit.com"
|
31
|
-
end
|
32
|
-
Thread.new do
|
33
|
-
loop do
|
34
|
-
TCPSocketMeasurer.report
|
35
|
-
puts "next report is in an hour"
|
36
|
-
sleep 3600
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
|
41
|
-
require "../boilerplate"
|
42
|
-
|
43
|
-
BOT = RedditBot::Bot.new YAML.load File.read "secrets.yaml"
|
44
3
|
|
45
|
-
|
46
|
-
require_relative "../../../../dimensioner/get_dimensions"
|
47
|
-
else
|
48
|
-
require_relative "#{Dir.home}/get_dimensions"
|
49
|
-
end
|
4
|
+
require "nokogiri"
|
50
5
|
|
6
|
+
require "gcplogger"
|
7
|
+
logger = GCPLogger.logger "largeimagesbot"
|
51
8
|
|
52
|
-
|
53
|
-
|
54
|
-
loop do
|
55
|
-
Hearthbeat.beat "u_largeimagesbot_r_largeimages", 310 unless Gem::Platform.local.os == "darwin"
|
56
|
-
puts "LOOP #{Time.now}"
|
9
|
+
require_relative "../get_dimensions"
|
10
|
+
Imgur.logger = logger
|
57
11
|
|
58
|
-
%w{
|
59
12
|
|
60
|
-
|
61
|
-
|
62
|
-
r/wtf
|
63
|
-
r/woahdude
|
64
|
-
|
65
|
-
r/earthporn
|
66
|
-
r/spaceporn
|
67
|
-
r/mapporn
|
68
|
-
r/historyporn
|
69
|
-
r/abandonedporn
|
70
|
-
r/macroporn
|
71
|
-
r/microporn
|
72
|
-
|
73
|
-
r/bigwallpapers
|
74
|
-
r/wallpapers
|
75
|
-
r/wallpaper
|
76
|
-
|
77
|
-
user/I_AM_STILL_A_IDIOT/m/nationalphotosubs
|
78
|
-
}
|
79
|
-
|
80
|
-
# r/highres
|
81
|
-
# r/bigwallpapers
|
82
|
-
# r/wtf
|
83
|
-
# r/funny
|
84
|
-
%w{
|
13
|
+
require "../boilerplate"
|
14
|
+
BOT = RedditBot::Bot.new YAML.load File.read "secrets.yaml"
|
85
15
|
|
16
|
+
INCLUDE = %w{
|
86
17
|
user/kjoneslol/m/sfwpornnetwork
|
87
18
|
|
88
19
|
r/woahdude
|
@@ -93,34 +24,62 @@ loop do
|
|
93
24
|
r/WQHD_Wallpaper
|
94
25
|
|
95
26
|
r/pic
|
27
|
+
}
|
28
|
+
EXCLUDE = %w{ foodporn powerwashingporn }
|
96
29
|
|
97
|
-
|
30
|
+
checked = []
|
98
31
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
32
|
+
loop do
|
33
|
+
logger.warn "LOOP #{Time.now}"
|
34
|
+
|
35
|
+
[ [:source_ultireddit, 5000000, ( Nokogiri::XML(NetHTTPUtils.request_data ENV["FEEDPCBR_URL"]).remove_namespaces!.xpath("feed/entry").map do |entry|
|
36
|
+
[
|
37
|
+
entry.at_xpath("id").text,
|
38
|
+
entry.at_xpath("link[@rel='via']")["href"],
|
39
|
+
entry.at_xpath("title").text,
|
40
|
+
entry.at_xpath("category")["term"],
|
41
|
+
entry.at_xpath("author/name").text,
|
42
|
+
entry.at_xpath("link[@rel='alternate']")["href"],
|
43
|
+
]
|
44
|
+
end ) ],
|
45
|
+
[:source_reddit, 10000000, ( INCLUDE.flat_map do |sortasub|
|
46
|
+
BOT.new_posts(sortasub).take(100).map do |child|
|
47
|
+
next if child["is_self"]
|
48
|
+
next if EXCLUDE.include? child["subreddit"].downcase
|
49
|
+
child.values_at(
|
50
|
+
*%w{ id url title subreddit author permalink }
|
51
|
+
).tap{ |_| _.last.prepend "https://www.reddit.com" }
|
52
|
+
end.compact
|
53
|
+
end ) ],
|
54
|
+
].each do |source, min_resolution, entries|
|
55
|
+
logger.warn "#{source}.size: #{entries.size}"
|
56
|
+
entries.each do |id, url, title, subreddit, author, permalink|
|
104
57
|
next if checked.include? id
|
105
58
|
checked << id
|
106
|
-
# id = "36y3w1"
|
107
|
-
# url = "http://i.imgur.com/c6uGJV0.jpg"
|
108
|
-
# unless (url = item["data"]["url"])[%r{//[^/]*imgur\.com/}]
|
109
59
|
# next if Gem::Platform.local.os == "darwin" # prevent concurrent posting
|
110
|
-
|
111
|
-
|
60
|
+
logger.debug "image url for #{id}: #{url}"
|
61
|
+
|
62
|
+
next logger.warn "skipped (GetDimensions :skipped) #{url} from http://redd.it/#{id}" if :skipped == _ = begin
|
63
|
+
GetDimensions::get_dimensions url
|
64
|
+
rescue GetDimensions::Error404
|
65
|
+
next logger.warn "skipped (GetDimensions::Error404) #{url} from http://redd.it/#{id}"
|
66
|
+
rescue GetDimensions::ErrorUnknown
|
67
|
+
next logger.warn "skipped (GetDimensions::ErrorUnknown) #{url} from http://redd.it/#{id}"
|
68
|
+
end
|
69
|
+
fail "unable #{url} from http://redd.it/#{id}" unless _
|
112
70
|
width, height, best_direct_url, *all_direct_urls = _
|
113
|
-
|
114
|
-
|
115
|
-
next
|
71
|
+
logger.info "GetDimensions: %p" % [[width, height, best_direct_url, all_direct_urls.size]]
|
72
|
+
unless min_resolution <= width * height
|
73
|
+
next logger.warn "skipped low resolution #{source}"
|
116
74
|
end
|
117
75
|
# next if Gem::Platform.local.os == "darwin" # prevent concurrent posting
|
118
76
|
# puts "https://www.reddit.com/r/LargeImages/search.json?q=url%3A#{CGI.escape url}&restrict_sr=on"
|
119
77
|
resolution = "[#{width}x#{height}]"
|
120
|
-
|
78
|
+
# require "cgi"
|
79
|
+
next logger.warn "already submitted #{resolution} #{id}: '#{url}'" unless
|
121
80
|
Gem::Platform.local.os == "darwin" ||
|
122
81
|
(JSON.parse NetHTTPUtils.request_data "https://www.reddit.com/r/LargeImages/search.json?q=url%3A#{CGI.escape url}&restrict_sr=on", header: ["User-Agent", "ajsdjasdasd"])["data"]["children"].empty?
|
123
|
-
|
82
|
+
logger.warn "resolution #{resolution} got from #{id}: #{url}"
|
124
83
|
# next if Gem::Platform.local.os == "darwin" # prevent concurrent posting
|
125
84
|
title = "#{resolution}#{
|
126
85
|
" [#{all_direct_urls.size} images]" if all_direct_urls.size > 1
|
@@ -130,9 +89,8 @@ loop do
|
|
130
89
|
sub(/(.{#{100 - subreddit.size}}).+/, '\1...')
|
131
90
|
} /r/#{subreddit}".
|
132
91
|
gsub(/\s+\(\s+\)\s+/, " ")
|
133
|
-
|
134
|
-
|
135
|
-
else
|
92
|
+
logger.warn "new post #{source}: #{url} #{title.inspect}"
|
93
|
+
unless Gem::Platform.local.os == "darwin"
|
136
94
|
result = BOT.json :post,
|
137
95
|
"/api/submit",
|
138
96
|
{
|
@@ -140,16 +98,9 @@ loop do
|
|
140
98
|
url: url,
|
141
99
|
sr: "LargeImages",
|
142
100
|
title: title,
|
143
|
-
# ["uh / X-Modhash header", ""]
|
144
101
|
}
|
145
|
-
# }.tap{ |form|
|
146
|
-
# form.merge!( {
|
147
|
-
# iden: BOT.iden_and_captcha[0],
|
148
|
-
# captcha: BOT.iden_and_captcha[1],
|
149
|
-
# } ) if BOT.iden_and_captcha
|
150
|
-
# }
|
151
102
|
next unless result["json"]["errors"].empty?
|
152
|
-
|
103
|
+
logger.info "post url: #{result["json"]["data"]["url"]}"
|
153
104
|
end
|
154
105
|
# {"json"=>
|
155
106
|
# {"errors"=>[],
|
@@ -158,26 +109,26 @@ loop do
|
|
158
109
|
# "https://www.reddit.com/r/LargeImages/comments/3a9rel/2594x1724_overlooking_wildhorse_lake_from_near/",
|
159
110
|
# "id"=>"3a9rel",
|
160
111
|
# "name"=>"t3_3a9rel"}}}
|
161
|
-
line1 = "[Original thread](
|
112
|
+
line1 = "[Original thread](#{permalink}) by /u/#{author}"
|
162
113
|
line2 = "Direct link#{" (the largest image)" if all_direct_urls.size > 1}: #{best_direct_url}"
|
163
114
|
line3 = [
|
164
115
|
"Direct links to all other images in album:",
|
165
116
|
all_direct_urls - [best_direct_url]
|
166
117
|
] if all_direct_urls.size > 1
|
167
118
|
text = [line1, line2, line3].compact.join(" \n")
|
168
|
-
|
169
|
-
|
170
|
-
else
|
119
|
+
logger.info "new comment: #{text.inspect}"
|
120
|
+
unless Gem::Platform.local.os == "darwin"
|
171
121
|
result = BOT.leave_a_comment "#{result["json"]["data"]["name"]}", text.sub(/(?<=.{9000}).+/m, "...")
|
172
122
|
unless result["json"]["errors"].empty?
|
173
|
-
|
123
|
+
logger.error result.inspect
|
174
124
|
fail "failed to leave comment"
|
175
125
|
end
|
176
126
|
end
|
177
|
-
|
127
|
+
|
128
|
+
abort if ENV["TEST"]
|
178
129
|
end
|
179
130
|
end
|
180
131
|
|
181
|
-
|
132
|
+
logger.warn "END LOOP #{Time.now}"
|
182
133
|
sleep 300
|
183
134
|
end
|
data/examples/mlgtv/channels.txt
CHANGED
data/examples/mlgtv/main.rb
CHANGED
@@ -96,6 +96,7 @@ loop do
|
|
96
96
|
"Modern Warfare 2" => "codmw2",
|
97
97
|
}.each do |game, css|
|
98
98
|
(begin
|
99
|
+
require "cgi"
|
99
100
|
begin
|
100
101
|
t = NetHTTPUtils.get_response "https://api.twitch.tv/kraken/streams?game=#{CGI::escape game}&access_token=#{File.read("twitch.token").strip}&client_id=#{File.read("client.id").strip}&channel=#{File.read("channels.txt").split.join ?,}"
|
101
102
|
end while t.code == 500
|
@@ -12,17 +12,17 @@ BOT = RedditBot::Bot.new YAML.load(File.read "secrets.yaml"), subreddit: SUBREDD
|
|
12
12
|
TWITTER = "RealTimeWWII"
|
13
13
|
|
14
14
|
tweet2titleNtext = lambda do |tweet|
|
15
|
-
pp tweet if
|
15
|
+
pp tweet if ENV["TEST"]
|
16
16
|
text = ""
|
17
17
|
contains_media = false
|
18
18
|
up = ->s{ s.split.map{ |w| "^#{w}" }.join " " }
|
19
|
-
if tweet["extended_entities"] && tweet["extended_entities"]["media"]
|
19
|
+
if tweet["extended_entities"] && !tweet["extended_entities"]["media"].empty?
|
20
20
|
contains_media = true
|
21
21
|
tweet["extended_entities"]["media"].each_with_index do |media, i|
|
22
22
|
text.concat "* [Image #{i + 1}](#{media["media_url_https"]})\n\n"
|
23
23
|
end
|
24
24
|
end
|
25
|
-
if tweet["entities"]["urls"]
|
25
|
+
if !tweet["entities"]["urls"].empty?
|
26
26
|
contains_media = true
|
27
27
|
tweet["entities"]["urls"].each_with_index do |url, i|
|
28
28
|
text.concat "* [Link #{i + 1}](#{url["expanded_url"]})\n\n"
|
@@ -37,15 +37,21 @@ tweet2titleNtext = lambda do |tweet|
|
|
37
37
|
[CGI::unescapeHTML(tweet["full_text"]).sub(/( https:\/\/t\.co\/[0-9a-zA-Z]{10})*\z/, ""), text, contains_media]
|
38
38
|
end
|
39
39
|
[
|
40
|
-
[905764294687633408, "The Polish government & military high command is now evacuating Warsaw for Brest, 120 miles east: German armies are too close to the capital", "* [Image 1](https://pbs.twimg.com/media/DJHq71BXYAA6KJ0.jpg)\n\n" "^- ^WW2 ^Tweets ^from ^1939 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^September ^7, ^2017](https://twitter.com/#{TWITTER}/status/905764294687633408)"],
|
41
|
-
[915534673471733760, "In east Poland (now Soviet Ukraine) industry & farms to be collectivised, political parties banned, aristocrats & capitalists \"re-educated\".", "* [Image 1](https://pbs.twimg.com/media/DLSh2J9W4AACcOG.jpg)\n\n* [Image 2](https://pbs.twimg.com/media/DLSh4sKX0AEBaXq.jpg)\n\n^- ^WW2 ^Tweets ^from ^1939 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| ""
|
42
|
-
[915208866408824832, "For 1st time, RAF planes dropping propaganda leaflets on Berlin itself, entitled \"Germans: these are your leaders!\"", "* [Image 1](https://pbs.twimg.com/media/DLN5jJ-XkAEUz9M.jpg)\n\n* [Link 1](https://www.psywar.org/product_1939EH158.php)\n\n" "^- ^WW2 ^Tweets ^from ^1939 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| ""
|
43
|
-
[914577848891006978, "\"In Poland, Russia pursued a cold policy of selfinterest. But clearly necessary for Russia… against Nazi menace.\"", "* [Link 1](https://www.youtube.com/watch?v=ygmP5A3n2JA)\n\n" "^- ^WW2 ^Tweets ^from ^1939 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| ""
|
44
|
-
].
|
40
|
+
[905764294687633408, true, "The Polish government & military high command is now evacuating Warsaw for Brest, 120 miles east: German armies are too close to the capital", "* [Image 1](https://pbs.twimg.com/media/DJHq71BXYAA6KJ0.jpg)\n\n" "^- ^WW2 ^Tweets ^from ^1939 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^""September ^7, ^2017](https://twitter.com/#{TWITTER}/status/905764294687633408)"],
|
41
|
+
[915534673471733760, true, "In east Poland (now Soviet Ukraine) industry & farms to be collectivised, political parties banned, aristocrats & capitalists \"re-educated\".", "* [Image 1](https://pbs.twimg.com/media/DLSh2J9W4AACcOG.jpg)\n\n* [Image 2](https://pbs.twimg.com/media/DLSh4sKX0AEBaXq.jpg)\n\n^- ^WW2 ^Tweets ^from ^1939 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "October ^4, ^2017](https://twitter.com/#{TWITTER}/status/915534673471733760)"],
|
42
|
+
[915208866408824832, true, "For 1st time, RAF planes dropping propaganda leaflets on Berlin itself, entitled \"Germans: these are your leaders!\"", "* [Image 1](https://pbs.twimg.com/media/DLN5jJ-XkAEUz9M.jpg)\n\n* [Link 1](https://www.psywar.org/product_1939EH158.php)\n\n" "^- ^WW2 ^Tweets ^from ^1939 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "October ^3, ^2017](https://twitter.com/#{TWITTER}/status/915208866408824832)"],
|
43
|
+
[914577848891006978, true, "\"In Poland, Russia pursued a cold policy of selfinterest. But clearly necessary for Russia… against Nazi menace.\"", "* [Link 1](https://www.youtube.com/watch?v=ygmP5A3n2JA)\n\n" "^- ^WW2 ^Tweets ^from ^1939 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "October ^1, ^2017](https://twitter.com/#{TWITTER}/status/914577848891006978)"],
|
44
|
+
[926581977372942336, false, "Finland rejects Soviet demand to surrender land near Leningrad & give Red Navy base in Hanko; Soviets now claim Finns' manner \"warlike\".", "^- ^WW2 ^Tweets ^from ^1939 [^\\(@#{TWITTER}\\)](https://twitter.com/#{TWITTER}) ^| [^" "November ^3, ^2017](https://twitter.com/#{TWITTER}/status/926581977372942336)"],
|
45
|
+
].each do |id, contains_media_, title_, text_|
|
45
46
|
title, text, contains_media = tweet2titleNtext[ JSON.load NetHTTPUtils.request_data(
|
46
47
|
"https://api.twitter.com/1.1/statuses/show.json?id=#{id}&tweet_mode=extended",
|
47
48
|
header: { Authorization: "Bearer #{TWITTER_ACCESS_TOKEN}" }
|
48
49
|
) ]
|
50
|
+
unless contains_media_ == contains_media
|
51
|
+
puts "expected: #{contains_media_}"
|
52
|
+
puts "got: #{contains_media}"
|
53
|
+
abort "CONTAINS_MEDIA ERROR"
|
54
|
+
end
|
49
55
|
unless title_ == title
|
50
56
|
puts "expected:\n#{title_.inspect}"
|
51
57
|
puts "got:\n#{title.inspect}"
|
@@ -79,16 +85,23 @@ loop do
|
|
79
85
|
flair["text"] == "Contains Media"
|
80
86
|
end
|
81
87
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
88
|
+
timeout = 0
|
89
|
+
JSON.load( begin
|
90
|
+
NetHTTPUtils.request_data(
|
91
|
+
"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=#{TWITTER}&count=200&tweet_mode=extended",
|
92
|
+
header: { Authorization: "Bearer #{TWITTER_ACCESS_TOKEN}" }
|
93
|
+
) do |res|
|
94
|
+
next unless res.key? "x-rate-limit-remaining"
|
95
|
+
remaining = res.fetch("x-rate-limit-remaining").to_i
|
96
|
+
next if 100 < remaining
|
97
|
+
t = (res.fetch("x-rate-limit-reset").to_i - Time.now.to_i + 1).fdiv remaining
|
98
|
+
puts "sleep #{t}"
|
99
|
+
sleep t
|
100
|
+
end
|
101
|
+
rescue NetHTTPUtils::Error => e
|
102
|
+
fail if e.code != 503
|
103
|
+
sleep(timeout += 1)
|
104
|
+
retry
|
92
105
|
end ).reverse_each do |tweet|
|
93
106
|
next if tweet["id"] <= id
|
94
107
|
# next unless tweet["id"] == 905724018996772865 # two media files
|
data/lib/reddit_bot.rb
CHANGED
@@ -236,21 +236,21 @@ module RedditBot
|
|
236
236
|
end
|
237
237
|
|
238
238
|
def _resp mtd, url, form, headers, base_auth = nil
|
239
|
-
|
240
|
-
|
241
|
-
x-ratelimit-remaining
|
242
|
-
x-ratelimit-used
|
243
|
-
x-ratelimit-reset
|
244
|
-
}.map{ |key| "#{key}=#{response.to_hash[key]}" }.join ", " \
|
239
|
+
NetHTTPUtils.get_response(url, mtd, form: form, header: headers, auth: base_auth).tap do |response|
|
240
|
+
next unless remaining = response.to_hash["x-ratelimit-remaining"]
|
245
241
|
if Gem::Platform.local.os == "darwin"
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
242
|
+
puts %w{
|
243
|
+
x-ratelimit-remaining
|
244
|
+
x-ratelimit-used
|
245
|
+
x-ratelimit-reset
|
246
|
+
}.map{ |key| "#{key}=#{response.to_hash[key]}" }.join ", "
|
247
|
+
end
|
248
|
+
fail remaining[0] if remaining[0].size < 4
|
249
|
+
next if remaining[0].size > 4
|
250
|
+
t = (response.to_hash["x-ratelimit-reset"][0].to_f + 1) / remaining[0].to_f + 1
|
251
|
+
puts "sleeping #{t} seconds because of x-ratelimit"
|
252
|
+
sleep t
|
253
|
+
end
|
254
254
|
end
|
255
255
|
|
256
256
|
end
|
data/lib/reddit_bot/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reddit_bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Maslov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -35,7 +35,10 @@ files:
|
|
35
35
|
- LICENSE.txt
|
36
36
|
- README.md
|
37
37
|
- Rakefile
|
38
|
+
- examples/.bashrc
|
38
39
|
- examples/.gitignore
|
40
|
+
- examples/Gemfile
|
41
|
+
- examples/Gemfile.lock
|
39
42
|
- examples/boilerplate.rb
|
40
43
|
- examples/councilofricks/Gemfile
|
41
44
|
- examples/councilofricks/Gemfile.lock
|
@@ -56,6 +59,7 @@ files:
|
|
56
59
|
- examples/devflairbot/Gemfile
|
57
60
|
- examples/devflairbot/Gemfile.lock
|
58
61
|
- examples/devflairbot/main.rb
|
62
|
+
- examples/get_dimensions.rb
|
59
63
|
- examples/iostroubleshooting/Gemfile
|
60
64
|
- examples/iostroubleshooting/Gemfile.lock
|
61
65
|
- examples/iostroubleshooting/main.rb
|