ayadn 2.1 → 3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +1 -2
- data/CHANGELOG.md +11 -0
- data/README.md +7 -9
- data/ayadn.gemspec +1 -2
- data/doc/02-install.md +11 -1
- data/doc/18-contact.md +0 -2
- data/lib/ayadn.rb +1 -1
- data/lib/ayadn/action.rb +13 -14
- data/lib/ayadn/annotations.rb +1 -1
- data/lib/ayadn/api.rb +8 -3
- data/lib/ayadn/app.rb +23 -11
- data/lib/ayadn/authorize.rb +47 -27
- data/lib/ayadn/cnx.rb +20 -3
- data/lib/ayadn/descriptions.rb +0 -12
- data/lib/ayadn/diagnostics.rb +471 -0
- data/lib/ayadn/endpoints.rb +47 -46
- data/lib/ayadn/extend.rb +20 -0
- data/lib/ayadn/fileops.rb +3 -3
- data/lib/ayadn/ids.rb +17 -0
- data/lib/ayadn/nicerank.rb +2 -0
- data/lib/ayadn/nowplaying.rb +12 -5
- data/lib/ayadn/post.rb +2 -0
- data/lib/ayadn/set.rb +78 -3
- data/lib/ayadn/settings.rb +20 -3
- data/lib/ayadn/status.rb +114 -62
- data/lib/ayadn/stream.rb +2 -0
- data/lib/ayadn/switch.rb +18 -11
- data/lib/ayadn/tvshow.rb +7 -3
- data/lib/ayadn/version.rb +1 -1
- data/lib/ayadn/view.rb +131 -82
- data/lib/ayadn/workers.rb +10 -11
- data/spec/mock/@ericd.json +4 -4
- data/spec/mock/ayadn.sqlite +0 -0
- data/spec/mock/files.json +2 -2
- data/spec/mock/fwr_@ayadn.json +4 -4
- data/spec/mock/int.json +13 -13
- data/spec/mock/mentions.json +4 -4
- data/spec/mock/nicerank.log +1 -1
- data/spec/mock/posted.json +1 -1
- data/spec/mock/regex.json +2 -2
- data/spec/unit/annotations_spec.rb +8 -8
- data/spec/unit/post_spec.rb +3 -3
- metadata +5 -20
- data/Guardfile +0 -26
- data/lib/ayadn/migration.rb +0 -431
data/lib/ayadn/endpoints.rb
CHANGED
@@ -4,9 +4,20 @@ module Ayadn
|
|
4
4
|
|
5
5
|
attr_accessor :ayadn_callback_url, :base_url, :config_api_url, :posts_url, :users_url, :files_url, :token_url, :channels_url, :pm_url
|
6
6
|
|
7
|
+
# Warning
|
8
|
+
# comment next line
|
9
|
+
require_relative "ids"
|
10
|
+
# uncomment and insert your own URL
|
11
|
+
# CALLBACK_URL = ""
|
12
|
+
|
7
13
|
def initialize
|
8
|
-
@ayadn_callback_url =
|
9
|
-
|
14
|
+
@ayadn_callback_url = CALLBACK_URL
|
15
|
+
api_file = Dir.home + "/ayadn/.api.yml"
|
16
|
+
@base_url = if File.exist?(api_file)
|
17
|
+
YAML.load(File.read(api_file))[:root] + "/"
|
18
|
+
else
|
19
|
+
"https://api.app.net/"
|
20
|
+
end
|
10
21
|
@config_api_url = @base_url + "config"
|
11
22
|
@posts_url = @base_url + "posts/"
|
12
23
|
@users_url = @base_url + "users/"
|
@@ -17,7 +28,7 @@ module Ayadn
|
|
17
28
|
end
|
18
29
|
|
19
30
|
def authorize_url
|
20
|
-
"https://account.app.net/oauth/authenticate?client_id=#{Settings::
|
31
|
+
"https://account.app.net/oauth/authenticate?client_id=#{Settings::CLIENT_ID}&response_type=token&redirect_uri=#{@ayadn_callback_url}&scope=basic,stream,write_post,follow,public_messages,messages,files,update_profile&include_marker=1"
|
21
32
|
end
|
22
33
|
|
23
34
|
def token_info
|
@@ -32,28 +43,42 @@ module Ayadn
|
|
32
43
|
"#{@files_url}?access_token=#{Settings.user_token}"
|
33
44
|
end
|
34
45
|
|
35
|
-
|
46
|
+
private
|
47
|
+
|
48
|
+
def make_options_list(options)
|
36
49
|
@options_list = if options[:count] || options[:since_id]
|
37
50
|
API.build_query(options)
|
38
51
|
else
|
52
|
+
yield
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def make_options_list_simple(options)
|
57
|
+
@options_list = if options[:count]
|
58
|
+
API.build_query(options)
|
59
|
+
else
|
60
|
+
yield
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
public
|
65
|
+
|
66
|
+
def unified(options)
|
67
|
+
make_options_list(options) do
|
39
68
|
API.build_query({count: Settings.options[:counts][:unified]})
|
40
69
|
end
|
41
70
|
"#{@posts_url}stream/unified?access_token=#{Settings.user_token}#{@options_list}"
|
42
71
|
end
|
43
72
|
|
44
73
|
def checkins(options)
|
45
|
-
|
46
|
-
API.build_query(options)
|
47
|
-
else
|
74
|
+
make_options_list(options) do
|
48
75
|
API.build_query({count: Settings.options[:counts][:checkins]})
|
49
76
|
end
|
50
77
|
"#{@posts_url}stream/explore/checkins?access_token=#{Settings.user_token}#{@options_list}"
|
51
78
|
end
|
52
79
|
|
53
80
|
def global(options)
|
54
|
-
|
55
|
-
API.build_query(options)
|
56
|
-
else
|
81
|
+
make_options_list(options) do
|
57
82
|
API.build_query({count: Settings.options[:counts][:global]})
|
58
83
|
end
|
59
84
|
if Settings.global[:force] == true
|
@@ -64,45 +89,35 @@ module Ayadn
|
|
64
89
|
end
|
65
90
|
|
66
91
|
def trending(options)
|
67
|
-
|
68
|
-
API.build_query(options)
|
69
|
-
else
|
92
|
+
make_options_list(options) do
|
70
93
|
API.build_query({count: Settings.options[:counts][:trending]})
|
71
94
|
end
|
72
95
|
"#{@posts_url}stream/explore/trending?access_token=#{Settings.user_token}#{@options_list}"
|
73
96
|
end
|
74
97
|
|
75
98
|
def photos(options)
|
76
|
-
|
77
|
-
API.build_query(options)
|
78
|
-
else
|
99
|
+
make_options_list(options) do
|
79
100
|
API.build_query({count: Settings.options[:counts][:photos]})
|
80
101
|
end
|
81
102
|
"#{@posts_url}stream/explore/photos?access_token=#{Settings.user_token}#{@options_list}"
|
82
103
|
end
|
83
104
|
|
84
105
|
def conversations(options)
|
85
|
-
|
86
|
-
API.build_query(options)
|
87
|
-
else
|
106
|
+
make_options_list(options) do
|
88
107
|
API.build_query({count: Settings.options[:counts][:conversations]})
|
89
108
|
end
|
90
109
|
"#{@posts_url}stream/explore/conversations?access_token=#{Settings.user_token}#{@options_list}"
|
91
110
|
end
|
92
111
|
|
93
112
|
def mentions(username, options)
|
94
|
-
|
95
|
-
API.build_query(options)
|
96
|
-
else
|
113
|
+
make_options_list_simple(options) do
|
97
114
|
API.build_query({count: Settings.options[:counts][:mentions]})
|
98
115
|
end
|
99
116
|
"#{@users_url}#{username}/mentions/?access_token=#{Settings.user_token}#{@options_list}"
|
100
117
|
end
|
101
118
|
|
102
119
|
def posts(username, options)
|
103
|
-
|
104
|
-
API.build_query(options)
|
105
|
-
else
|
120
|
+
make_options_list_simple(options) do
|
106
121
|
API.build_query({count: Settings.options[:counts][:posts]})
|
107
122
|
end
|
108
123
|
if Settings.global[:force] == true
|
@@ -113,9 +128,7 @@ module Ayadn
|
|
113
128
|
end
|
114
129
|
|
115
130
|
def whatstarred(username, options)
|
116
|
-
|
117
|
-
API.build_query(options)
|
118
|
-
else
|
131
|
+
make_options_list_simple(options) do
|
119
132
|
API.build_query({count: Settings.options[:counts][:default]})
|
120
133
|
end
|
121
134
|
"#{@users_url}#{username}/stars/?access_token=#{Settings.user_token}#{@options_list}"
|
@@ -134,9 +147,7 @@ module Ayadn
|
|
134
147
|
end
|
135
148
|
|
136
149
|
def convo(post_id, options)
|
137
|
-
|
138
|
-
API.build_query(options)
|
139
|
-
else
|
150
|
+
make_options_list_simple(options) do
|
140
151
|
API.build_query({count: Settings.options[:counts][:convo]})
|
141
152
|
end
|
142
153
|
"#{@posts_url}#{post_id}/replies/?access_token=#{Settings.user_token}#{@options_list}"
|
@@ -163,36 +174,28 @@ module Ayadn
|
|
163
174
|
end
|
164
175
|
|
165
176
|
def search(words, options)
|
166
|
-
|
167
|
-
API.build_query(options)
|
168
|
-
else
|
177
|
+
make_options_list_simple(options) do
|
169
178
|
API.build_query({count: Settings.options[:counts][:search]})
|
170
179
|
end
|
171
180
|
"#{@posts_url}search?text=#{words}&access_token=#{Settings.user_token}#{@options_list}"
|
172
181
|
end
|
173
182
|
|
174
183
|
def search_users words, options
|
175
|
-
|
176
|
-
API.build_query(options)
|
177
|
-
else
|
184
|
+
make_options_list_simple(options) do
|
178
185
|
API.build_query({count: Settings.options[:counts][:search]})
|
179
186
|
end
|
180
187
|
"#{@users_url}search?q=#{words}&access_token=#{Settings.user_token}#{@options_list}"
|
181
188
|
end
|
182
189
|
|
183
190
|
def search_annotations anno, options
|
184
|
-
|
185
|
-
API.build_query(options)
|
186
|
-
else
|
191
|
+
make_options_list_simple(options) do
|
187
192
|
API.build_query({count: Settings.options[:counts][:search]})
|
188
193
|
end
|
189
194
|
"#{@posts_url}search?annotation_types=#{anno}&access_token=#{Settings.user_token}#{@options_list}"
|
190
195
|
end
|
191
196
|
|
192
197
|
def search_messages channel_id, words, options
|
193
|
-
|
194
|
-
API.build_query(options)
|
195
|
-
else
|
198
|
+
make_options_list_simple(options) do
|
196
199
|
API.build_query({count: Settings.options[:counts][:search]})
|
197
200
|
end
|
198
201
|
"#{@channels_url}messages/search?query=#{words}&channel_ids=#{channel_id}&access_token=#{Settings.user_token}#{@options_list}"
|
@@ -216,9 +219,7 @@ module Ayadn
|
|
216
219
|
end
|
217
220
|
|
218
221
|
def files_list(options)
|
219
|
-
|
220
|
-
API.build_query(options)
|
221
|
-
else
|
222
|
+
make_options_list_simple(options) do
|
222
223
|
API.build_query({count: Settings.options[:counts][:files]})
|
223
224
|
end
|
224
225
|
"#{@users_url}me/files?access_token=#{Settings.user_token}#{@options_list}"
|
data/lib/ayadn/extend.rb
CHANGED
@@ -22,3 +22,23 @@ class Integer
|
|
22
22
|
}.each_pair { |e, s| return "#{(self.to_f / (s / 1024)).round(2)} #{e}" if self < s }
|
23
23
|
end
|
24
24
|
end
|
25
|
+
class Object
|
26
|
+
def blank?
|
27
|
+
respond_to?(:empty?) ? !!empty? : !self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
class Hash
|
31
|
+
def deep_diff(b)
|
32
|
+
a = self
|
33
|
+
(a.keys | b.keys).inject({}) do |diff, k|
|
34
|
+
if a[k] != b[k]
|
35
|
+
if a[k].respond_to?(:deep_diff) && b[k].respond_to?(:deep_diff)
|
36
|
+
diff[k] = a[k].deep_diff(b[k])
|
37
|
+
else
|
38
|
+
diff[k] = [a[k], b[k]]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
diff
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/ayadn/fileops.rb
CHANGED
@@ -59,11 +59,11 @@ module Ayadn
|
|
59
59
|
begin
|
60
60
|
case File.extname(file).downcase
|
61
61
|
when ".png"
|
62
|
-
`curl -k -H 'Authorization: BEARER #{token}'
|
62
|
+
`curl -k -H 'Authorization: BEARER #{token}' #{Settings.config[:api][:baseURL]}/files -F 'type=com.ayadn.files' -F "content=@#{file};type=image/png" -F 'public=true' -X POST`
|
63
63
|
when ".gif"
|
64
|
-
`curl -k -H 'Authorization: BEARER #{token}'
|
64
|
+
`curl -k -H 'Authorization: BEARER #{token}' #{Settings.config[:api][:baseURL]}/files -F 'type=com.ayadn.files' -F "content=@#{file};type=image/gif" -F 'public=true' -X POST`
|
65
65
|
else #jpg or jpeg or JPG or JPEG, automatically recognized as such
|
66
|
-
`curl -k -H 'Authorization: BEARER #{token}'
|
66
|
+
`curl -k -H 'Authorization: BEARER #{token}' #{Settings.config[:api][:baseURL]}/files -F 'type=com.ayadn.files' -F "content=@#{file}" -F 'public=true' -X POST`
|
67
67
|
end
|
68
68
|
rescue Errno::ENOENT
|
69
69
|
Status.new.no_curl
|
data/lib/ayadn/ids.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Ayadn
|
3
|
+
class Settings
|
4
|
+
CLIENT_ID = "hFsCGArAjgJkYBHTHbZnUvzTmL4vaLHL"
|
5
|
+
end
|
6
|
+
class TvShow
|
7
|
+
TVDB_API_KEY = 'E874ACBC542CAA53'
|
8
|
+
end
|
9
|
+
class Endpoints
|
10
|
+
CALLBACK_URL = "http://aya.io/ayadn/auth.html"
|
11
|
+
end
|
12
|
+
class NowPlaying
|
13
|
+
AFFILIATE_SUFFIX = "&at=1l3vtb8&ct=ayadn"
|
14
|
+
DEEZER_APP_ID = "150971"
|
15
|
+
DEEZER_AUTH_URL = "http://aya.io/ayadn/deezer.html"
|
16
|
+
end
|
17
|
+
end
|
data/lib/ayadn/nicerank.rb
CHANGED
data/lib/ayadn/nowplaying.rb
CHANGED
@@ -3,6 +3,14 @@ module Ayadn
|
|
3
3
|
|
4
4
|
class NowPlaying
|
5
5
|
|
6
|
+
# Warning
|
7
|
+
# comment next line
|
8
|
+
require_relative "ids"
|
9
|
+
# uncomment next line and insert your own codes
|
10
|
+
# AFFILIATE_SUFFIX = ""
|
11
|
+
# DEEZER_APP_ID = ""
|
12
|
+
# DEEZER_AUTH_URL = ""
|
13
|
+
|
6
14
|
begin
|
7
15
|
require 'rss'
|
8
16
|
rescue LoadError => e
|
@@ -25,9 +33,8 @@ module Ayadn
|
|
25
33
|
@custom_text = nil
|
26
34
|
else
|
27
35
|
@custom_text = "\n \n#{options[:text].join(' ')}"
|
28
|
-
end
|
29
|
-
@
|
30
|
-
@deezer_auth_url = "https://connect.deezer.com/oauth/auth.php?app_id=150971&redirect_uri=http://aya.io/ayadn/deezer.html&response_type=token&perms=basic_access,listening_history,offline_access"
|
36
|
+
end
|
37
|
+
@auth_url = "https://connect.deezer.com/oauth/auth.php?app_id=#{DEEZER_APP_ID}&redirect_uri=#{DEEZER_AUTH_URL}&response_type=token&perms=basic_access,listening_history,offline_access"
|
31
38
|
end
|
32
39
|
|
33
40
|
def deezer options
|
@@ -203,7 +210,7 @@ module Ayadn
|
|
203
210
|
|
204
211
|
def ask_deezer_user
|
205
212
|
@status.info("please", "open this link to authorize Deezer", "yellow")
|
206
|
-
@status.say { @
|
213
|
+
@status.say { @status.say_green :link, @auth_url }
|
207
214
|
@status.info("next", "paste the authorization code here", "cyan")
|
208
215
|
print "> "
|
209
216
|
begin
|
@@ -274,7 +281,7 @@ module Ayadn
|
|
274
281
|
'artist' => candidate['artistName'],
|
275
282
|
'track' => candidate['trackName'],
|
276
283
|
'preview' => candidate['previewUrl'],
|
277
|
-
'link' => "#{candidate['collectionViewUrl']}#{
|
284
|
+
'link' => "#{candidate['collectionViewUrl']}#{AFFILIATE_SUFFIX}",
|
278
285
|
'artwork' => candidate['artworkUrl100'].gsub('100x100', '1200x1200'),
|
279
286
|
'artwork_thumb' => candidate['artworkUrl100'].gsub('100x100', '600x600'),
|
280
287
|
'request' => url,
|
data/lib/ayadn/post.rb
CHANGED
data/lib/ayadn/set.rb
CHANGED
@@ -132,6 +132,23 @@ module Ayadn
|
|
132
132
|
counts_config.save
|
133
133
|
end
|
134
134
|
|
135
|
+
desc "edit", "Edit settings in $EDITOR"
|
136
|
+
def edit
|
137
|
+
Settings.load_config()
|
138
|
+
sets = Settings.config[:paths][:config] + "/config.yml"
|
139
|
+
if sets.blank?
|
140
|
+
Status.new.not_authorized
|
141
|
+
exit
|
142
|
+
end
|
143
|
+
ed = `echo $EDITOR`
|
144
|
+
if ed.blank?
|
145
|
+
Status.new.info "No predefined EDITOR, opening in VIM"
|
146
|
+
`vim #{sets}`
|
147
|
+
exit
|
148
|
+
end
|
149
|
+
`$EDITOR #{sets}`
|
150
|
+
end
|
151
|
+
|
135
152
|
desc "color ITEM COLOR", "Set ITEM to COLOR"
|
136
153
|
long_desc Descriptions.set_color
|
137
154
|
map "colors" => :color
|
@@ -202,10 +219,44 @@ module Ayadn
|
|
202
219
|
formats_config.save
|
203
220
|
end
|
204
221
|
|
222
|
+
desc "api URL", "Set an alternative base URL for the API calls."
|
223
|
+
def api(*args)
|
224
|
+
if args[0]
|
225
|
+
begin
|
226
|
+
SetAPI.new.setURL(args[0])
|
227
|
+
rescue NoMethodError, ArgumentError => e
|
228
|
+
Status.new.error_missing_parameters
|
229
|
+
exit
|
230
|
+
rescue => e
|
231
|
+
raise e
|
232
|
+
end
|
233
|
+
else
|
234
|
+
Status.new.error_missing_parameters
|
235
|
+
exit
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
205
239
|
end
|
206
240
|
|
207
241
|
class Validators
|
208
242
|
|
243
|
+
def self.URL(str)
|
244
|
+
require 'net/http'
|
245
|
+
if(str.to_s.empty?)
|
246
|
+
Status.new.error_missing_parameters
|
247
|
+
exit
|
248
|
+
end
|
249
|
+
begin
|
250
|
+
URI.parse(str)
|
251
|
+
# if url.host.nil? || (url.scheme != 'http' && url.scheme != 'https')
|
252
|
+
# ask: are you sure about this url?
|
253
|
+
# end
|
254
|
+
# url
|
255
|
+
rescue URI::Error => e
|
256
|
+
return nil
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
209
260
|
def self.boolean(value)
|
210
261
|
case value.downcase
|
211
262
|
when "true", "1", "yes"
|
@@ -271,7 +322,6 @@ module Ayadn
|
|
271
322
|
Settings.get_token()
|
272
323
|
Settings.init_config()
|
273
324
|
Logs.create_logger()
|
274
|
-
@thor = Thor::Shell::Color.new
|
275
325
|
@status = Status.new
|
276
326
|
end
|
277
327
|
|
@@ -282,14 +332,39 @@ module Ayadn
|
|
282
332
|
|
283
333
|
def log
|
284
334
|
@status.say do
|
285
|
-
@
|
286
|
-
@
|
335
|
+
@status.say_cyan :updated, "'#{@input}' in '#{@category}'"
|
336
|
+
@status.say_green :content, "'#{@output}'"
|
287
337
|
end
|
288
338
|
Logs.rec.info "new value for '#{@input}' in '#{@category}' => '#{@output}'"
|
289
339
|
end
|
290
340
|
|
291
341
|
end
|
292
342
|
|
343
|
+
class SetAPI < SetBase
|
344
|
+
|
345
|
+
def initialize
|
346
|
+
super
|
347
|
+
@category = 'API'
|
348
|
+
@status = Status.new
|
349
|
+
end
|
350
|
+
|
351
|
+
def setURL(url)
|
352
|
+
@input = url
|
353
|
+
# @status.say_header "checking URL validity"
|
354
|
+
url = Validators.URL(url)
|
355
|
+
if url != nil
|
356
|
+
@output = url.to_s
|
357
|
+
@status.say_info "setting up configuration"
|
358
|
+
File.write(Dir.home + "/ayadn/.api.yml", {root: @output}.to_yaml)
|
359
|
+
log()
|
360
|
+
else
|
361
|
+
@status.say_red :canceled, "URL is invalid"
|
362
|
+
exit
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
end
|
367
|
+
|
293
368
|
class SetFormats < SetBase
|
294
369
|
|
295
370
|
def initialize
|
data/lib/ayadn/settings.rb
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
module Ayadn
|
3
3
|
class Settings
|
4
4
|
|
5
|
-
|
5
|
+
# Warning
|
6
|
+
# comment next line
|
7
|
+
require_relative "ids"
|
8
|
+
# uncomment and insert your own client id
|
9
|
+
# CLIENT_ID = ""
|
6
10
|
|
7
11
|
class << self
|
8
12
|
attr_accessor :options, :config, :global
|
@@ -11,7 +15,17 @@ module Ayadn
|
|
11
15
|
|
12
16
|
def self.load_config
|
13
17
|
active = self.check_for_accounts
|
18
|
+
if active.blank?
|
19
|
+
Status.new.not_authorized
|
20
|
+
exit
|
21
|
+
end
|
14
22
|
home = active[3]
|
23
|
+
api_file = Dir.home + "/ayadn/.api.yml"
|
24
|
+
baseURL = if File.exist?(api_file)
|
25
|
+
YAML.load(File.read(api_file))[:root]
|
26
|
+
else
|
27
|
+
"https://api.app.net"
|
28
|
+
end
|
15
29
|
@config = {
|
16
30
|
paths: {
|
17
31
|
home: home,
|
@@ -28,6 +42,9 @@ module Ayadn
|
|
28
42
|
id: active[1],
|
29
43
|
username: active[0],
|
30
44
|
handle: active[2]
|
45
|
+
},
|
46
|
+
api: {
|
47
|
+
baseURL: baseURL
|
31
48
|
}
|
32
49
|
}
|
33
50
|
@options = self.defaults
|
@@ -43,10 +60,10 @@ module Ayadn
|
|
43
60
|
else
|
44
61
|
if File.exist?(Dir.home + "/ayadn/accounts.db")
|
45
62
|
# Ayadn 1.x with already authorized account(s)
|
46
|
-
status.
|
63
|
+
status.deprecated_ayadn
|
47
64
|
exit
|
48
65
|
else
|
49
|
-
# Ayadn
|
66
|
+
# Ayadn without any authorized account (gem installed but no ~/ayadn folder)
|
50
67
|
status.not_authorized
|
51
68
|
exit
|
52
69
|
end
|