unclekryon 0.4.9.pre.alpha

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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +34 -0
  3. data/Gemfile.lock +43 -0
  4. data/LICENSE +674 -0
  5. data/README.md +55 -0
  6. data/Rakefile +59 -0
  7. data/bin/unclekryon +30 -0
  8. data/iso/can_provs_terrs.yaml +54 -0
  9. data/iso/countries.yaml +3050 -0
  10. data/iso/iso.yaml +8 -0
  11. data/iso/languages.yaml +5641 -0
  12. data/iso/regions.yaml +42 -0
  13. data/iso/subregions.yaml +6 -0
  14. data/iso/usa_states.yaml +230 -0
  15. data/lib/unclekryon.rb +384 -0
  16. data/lib/unclekryon/data/album_data.rb +147 -0
  17. data/lib/unclekryon/data/artist_data.rb +109 -0
  18. data/lib/unclekryon/data/artist_data_data.rb +146 -0
  19. data/lib/unclekryon/data/aum_data.rb +75 -0
  20. data/lib/unclekryon/data/base_data.rb +79 -0
  21. data/lib/unclekryon/data/pic_data.rb +76 -0
  22. data/lib/unclekryon/data/release_data.rb +57 -0
  23. data/lib/unclekryon/data/social_data.rb +39 -0
  24. data/lib/unclekryon/data/timespan_data.rb +70 -0
  25. data/lib/unclekryon/dev_opts.rb +41 -0
  26. data/lib/unclekryon/hacker.rb +327 -0
  27. data/lib/unclekryon/iso.rb +341 -0
  28. data/lib/unclekryon/iso/base_iso.rb +196 -0
  29. data/lib/unclekryon/iso/can_prov_terr.rb +113 -0
  30. data/lib/unclekryon/iso/country.rb +133 -0
  31. data/lib/unclekryon/iso/language.rb +241 -0
  32. data/lib/unclekryon/iso/region.rb +53 -0
  33. data/lib/unclekryon/iso/subregion.rb +53 -0
  34. data/lib/unclekryon/iso/usa_state.rb +106 -0
  35. data/lib/unclekryon/jsoner.rb +124 -0
  36. data/lib/unclekryon/log.rb +111 -0
  37. data/lib/unclekryon/parsers/kryon_aum_year_album_parser.rb +499 -0
  38. data/lib/unclekryon/parsers/kryon_aum_year_parser.rb +413 -0
  39. data/lib/unclekryon/server.rb +29 -0
  40. data/lib/unclekryon/trainer.rb +231 -0
  41. data/lib/unclekryon/uploader.rb +29 -0
  42. data/lib/unclekryon/util.rb +228 -0
  43. data/lib/unclekryon/version.rb +26 -0
  44. data/unclekryon.gemspec +67 -0
  45. metadata +189 -0
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ #--
6
+ # This file is part of UncleKryon-server.
7
+ # Copyright (c) 2017-2019 Jonathan Bradley Whited (@esotericpig)
8
+ #
9
+ # UncleKryon-server is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # UncleKryon-server is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with UncleKryon-server. If not, see <https://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ require 'bundler/setup'
25
+
26
+ module UncleKryon
27
+ class Uploader
28
+ end
29
+ end
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ #--
6
+ # This file is part of UncleKryon-server.
7
+ # Copyright (c) 2017-2019 Jonathan Bradley Whited (@esotericpig)
8
+ #
9
+ # UncleKryon-server is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # UncleKryon-server is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with UncleKryon-server. If not, see <https://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ require 'date'
25
+ require 'fileutils'
26
+ require 'uri'
27
+
28
+ require 'net/http'
29
+
30
+ require 'unclekryon/dev_opts'
31
+ require 'unclekryon/log'
32
+
33
+ module UncleKryon
34
+ module Util
35
+ DATE_FORMAT = '%F'
36
+ DATETIME_FORMAT = '%F %T'
37
+
38
+ def self.add_trail_slash(url)
39
+ #url = url + '/' if url !~ /\/\z/
40
+ #return url
41
+
42
+ return File.join(url,'')
43
+ end
44
+
45
+ def self.clean_charset(str)
46
+ return str.encode('utf-8','MacRoman',universal_newline: true) # X-MAC-ROMAN
47
+ end
48
+
49
+ def self.clean_data(str)
50
+ # Have to use "[[:space:]]" for "&nbsp;" and "<br/>"
51
+ # This is necessary for "<br />\s+" (see 2015 "KRYON IN LIMA, PERU (2)")
52
+ str = str.clone()
53
+ str.gsub!(/[[:space:]]+/,' ') # Replace all spaces with one space
54
+ str.strip!()
55
+ return clean_charset(str)
56
+ end
57
+
58
+ def self.clean_link(url,link)
59
+ if url !~ /\/\z/
60
+ # Don't know if the end is a filename or a dirname, so just assume it is a filename and chop it off
61
+ url = File.dirname(url)
62
+ url = add_trail_slash(url)
63
+ end
64
+
65
+ # 1st, handle "/" (because you won't have "/../filename", which is invalid)
66
+ slash_regex = /\A(\/+\.*\/*)+/
67
+
68
+ if link =~ slash_regex
69
+ link = link.gsub(slash_regex,'')
70
+ link = get_top_link(url) + link # get_top_link(...) adds a slash
71
+
72
+ return link # Already handles "../" or "./" in the regex
73
+ end
74
+
75
+ # 2nd, handle "../" (and potentially "../././/" or "..//")
76
+ # - Ignores "./" if has it
77
+ dotdot_regex = /\A(\.\.\/)((\.\/)*(\/)*)*/ # \A (../) ( (./)* (/)* )*
78
+ num_dirs = 0 # Could be a boolean; left as int because of legacy code
79
+
80
+ while link =~ dotdot_regex
81
+ num_dirs = num_dirs + 1
82
+ link = link.gsub(dotdot_regex,'')
83
+ url = File.dirname(url)
84
+ end
85
+
86
+ if num_dirs > 0
87
+ link = add_trail_slash(url) + link
88
+
89
+ return link # Already handled "./" in the regex
90
+ end
91
+
92
+ # 3rd, handle "./"
93
+ dot_regex = /\A(\.\/+)+/
94
+
95
+ if link =~ dot_regex
96
+ link = link.gsub(dot_regex,'')
97
+ link = url + link # Slash already added at top of method
98
+
99
+ return link
100
+ end
101
+
102
+ # 4th, handle no path
103
+ #if link !~ /#{get_top_link(url)}/i
104
+ if link !~ /\Ahttps?:/i
105
+ link = url + link
106
+ else
107
+ link = link.sub(/\Ahttp:/i,'https:')
108
+ end
109
+
110
+ return link
111
+ end
112
+
113
+ def self.empty_s?(str)
114
+ return str.nil?() || str.gsub(/[[:space:]]+/,'').empty?()
115
+ end
116
+
117
+ def self.fix_link(url)
118
+ # If we do URI.escape(), then if it's already "%20",
119
+ # then it will convert it to "%2520"
120
+
121
+ url = url.gsub(/[[:space:]]/,'%20')
122
+
123
+ return url
124
+ end
125
+
126
+ def self.fix_shortwith_text(text)
127
+ if text =~ /w\/[[:alnum:]]/i
128
+ # I think it looks better with a space, personally.
129
+ # Some grammar guides say no space, but the Chicago style guide says there should be a space when it
130
+ # is a word by itself.
131
+ text = text.gsub(/w\//i,'w/ ')
132
+ end
133
+
134
+ return text
135
+ end
136
+
137
+ def self.format_date(date)
138
+ return date.nil?() ? nil : date.strftime(DATE_FORMAT)
139
+ end
140
+
141
+ def self.format_datetime(datetime)
142
+ return datetime.nil?() ? nil : datetime.strftime(DATETIME_FORMAT)
143
+ end
144
+
145
+ def self.get_top_link(url)
146
+ raise "No top link: #{url}" if DevOpts.instance.dev?() && url !~ /\Ahttps?\:/i
147
+
148
+ http_regex = /\Ahttps?\:|\A\./i # Check '.' to prevent infinite loop
149
+
150
+ while File.basename(File.dirname(url)) !~ http_regex
151
+ url = File.dirname(url).strip()
152
+
153
+ break if url == '.' || url.empty?()
154
+ end
155
+
156
+ return add_trail_slash(url)
157
+ end
158
+
159
+ def self.get_url_header_data(url)
160
+ uri = URI(url)
161
+ r = {}
162
+
163
+ Net::HTTP.start(uri.host,uri.port) do |http|
164
+ resp = http.request_head(uri)
165
+ r = resp.to_hash()
166
+ end
167
+
168
+ return r
169
+ end
170
+
171
+ def self.hash_def(hash,keys,value)
172
+ v = hash
173
+
174
+ for i in 0..keys.length-2
175
+ v = v[keys[i]]
176
+ end
177
+
178
+ v[keys[keys.length-1]] = value if v[keys[keys.length-1]].nil?()
179
+ return v[keys[keys.length-1]]
180
+ end
181
+
182
+ def self.hash_def_all(hash,keys,value)
183
+ v = hash
184
+
185
+ for i in 0..keys.length-2
186
+ if v[keys[i]].nil?()
187
+ v[keys[i]] = {}
188
+ v = v[keys[i]]
189
+ end
190
+ end
191
+
192
+ v[keys[keys.length-1]] = value if v[keys[keys.length-1]].nil?()
193
+ return v[keys[keys.length-1]]
194
+ end
195
+
196
+ def self.mk_dirs_from_filepath(filepath)
197
+ dirname = File.dirname(filepath)
198
+
199
+ if !dirname.nil?()
200
+ raise "Spaces around dirname: '#{dirname}'" if dirname != dirname.strip()
201
+
202
+ if !Dir.exist?(dirname)
203
+ Log.instance.info("Making dirs: '#{dirname}'...")
204
+ FileUtils.mkdir_p(dirname)
205
+ end
206
+ end
207
+ end
208
+
209
+ def self.parse_date_s(str)
210
+ return self.empty_s?(str) ? nil : Date.strptime(str,DATE_FORMAT)
211
+ end
212
+
213
+ def self.parse_datetime_s(str)
214
+ return self.empty_s?(str) ? nil : DateTime.strptime(str,DATETIME_FORMAT)
215
+ end
216
+
217
+ def self.parse_url_filename(url)
218
+ uri = URI.parse(url)
219
+ r = File.basename(uri.path)
220
+ r = URI.unescape(r)
221
+ return r.strip()
222
+ end
223
+
224
+ def self.safe_max(a,b)
225
+ return a.nil?() ? b : (b.nil?() ? a : ((a > b) ? a : b))
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ #--
6
+ # This file is part of UncleKryon-server.
7
+ # Copyright (c) 2017-2019 Jonathan Bradley Whited (@esotericpig)
8
+ #
9
+ # UncleKryon-server is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # UncleKryon-server is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with UncleKryon-server. If not, see <https://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ module UncleKryon
25
+ VERSION = '0.4.9-alpha'
26
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ #--
5
+ # This file is part of UncleKryon-server.
6
+ # Copyright (c) 2017-2019 Jonathan Bradley Whited (@esotericpig)
7
+ #
8
+ # UncleKryon-server is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # UncleKryon-server is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with UncleKryon-server. If not, see <https://www.gnu.org/licenses/>.
20
+ #++
21
+
22
+
23
+ lib = File.expand_path(File.join('..','lib'),__FILE__)
24
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
25
+
26
+ require 'unclekryon/version'
27
+
28
+ Gem::Specification.new() do |spec|
29
+ spec.name = 'unclekryon'
30
+ spec.version = UncleKryon::VERSION
31
+ spec.authors = ['Jonathan Bradley Whited (@esotericpig)']
32
+ spec.email = ['bradley@esotericpig.com']
33
+ spec.licenses = ['GPL-3.0-or-later']
34
+ spec.homepage = 'https://github.com/esotericpig/UncleKryon-server'
35
+ spec.summary = 'Uncle Kryon server (& hacker).'
36
+ spec.description = 'Uncle Kryon server (& hacker) for the Uncle Kryon mobile apps.'
37
+
38
+ spec.metadata = {
39
+ 'bug_tracker_uri' => 'https://github.com/esotericpig/UncleKryon-server/issues',
40
+ 'homepage_uri' => 'https://github.com/esotericpig/UncleKryon-server',
41
+ 'source_code_uri' => 'https://github.com/esotericpig/UncleKryon-server'
42
+ }
43
+
44
+ spec.require_paths = ['lib']
45
+ spec.bindir = 'bin'
46
+ spec.executables = [spec.name]
47
+
48
+ spec.files = Dir.glob(File.join("{#{spec.require_paths.join(',')}}",'**','*.{rb}')) +
49
+ Dir.glob(File.join(spec.bindir,'*')) +
50
+ Dir.glob(File.join("{iso,test}",'**','*.{rb,yaml}')) +
51
+ %W( Gemfile Gemfile.lock #{spec.name}.gemspec Rakefile ) +
52
+ %w( LICENSE README.md )
53
+
54
+ spec.required_ruby_version = '>= 2.4.0'
55
+ spec.requirements << 'Nokogiri: https://www.nokogiri.org/tutorials/installing_nokogiri.html'
56
+
57
+ spec.add_runtime_dependency 'nbayes' ,'~> 0.1.2' # For training type of text (machine learning)
58
+ spec.add_runtime_dependency 'nokogiri','~> 1.10' # For hacking HTML
59
+
60
+ spec.add_development_dependency 'bundler' ,'~> 2.1'
61
+ spec.add_development_dependency 'irb' ,'~> 1.2'
62
+ spec.add_development_dependency 'minitest','~> 5.14' # For testing
63
+ spec.add_development_dependency 'rake' ,'~> 13.0'
64
+ spec.add_development_dependency 'raketeer','~> 0.2' # For Nokogiri & IRB rake tasks
65
+
66
+ spec.post_install_message = "You can now use [#{spec.executables.join(', ')}] on the command line."
67
+ end
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unclekryon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.9.pre.alpha
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Bradley Whited (@esotericpig)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nbayes
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.10'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: irb
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '5.14'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.14'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '13.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '13.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: raketeer
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.2'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.2'
111
+ description: Uncle Kryon server (& hacker) for the Uncle Kryon mobile apps.
112
+ email:
113
+ - bradley@esotericpig.com
114
+ executables:
115
+ - unclekryon
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - Gemfile
120
+ - Gemfile.lock
121
+ - LICENSE
122
+ - README.md
123
+ - Rakefile
124
+ - bin/unclekryon
125
+ - iso/can_provs_terrs.yaml
126
+ - iso/countries.yaml
127
+ - iso/iso.yaml
128
+ - iso/languages.yaml
129
+ - iso/regions.yaml
130
+ - iso/subregions.yaml
131
+ - iso/usa_states.yaml
132
+ - lib/unclekryon.rb
133
+ - lib/unclekryon/data/album_data.rb
134
+ - lib/unclekryon/data/artist_data.rb
135
+ - lib/unclekryon/data/artist_data_data.rb
136
+ - lib/unclekryon/data/aum_data.rb
137
+ - lib/unclekryon/data/base_data.rb
138
+ - lib/unclekryon/data/pic_data.rb
139
+ - lib/unclekryon/data/release_data.rb
140
+ - lib/unclekryon/data/social_data.rb
141
+ - lib/unclekryon/data/timespan_data.rb
142
+ - lib/unclekryon/dev_opts.rb
143
+ - lib/unclekryon/hacker.rb
144
+ - lib/unclekryon/iso.rb
145
+ - lib/unclekryon/iso/base_iso.rb
146
+ - lib/unclekryon/iso/can_prov_terr.rb
147
+ - lib/unclekryon/iso/country.rb
148
+ - lib/unclekryon/iso/language.rb
149
+ - lib/unclekryon/iso/region.rb
150
+ - lib/unclekryon/iso/subregion.rb
151
+ - lib/unclekryon/iso/usa_state.rb
152
+ - lib/unclekryon/jsoner.rb
153
+ - lib/unclekryon/log.rb
154
+ - lib/unclekryon/parsers/kryon_aum_year_album_parser.rb
155
+ - lib/unclekryon/parsers/kryon_aum_year_parser.rb
156
+ - lib/unclekryon/server.rb
157
+ - lib/unclekryon/trainer.rb
158
+ - lib/unclekryon/uploader.rb
159
+ - lib/unclekryon/util.rb
160
+ - lib/unclekryon/version.rb
161
+ - unclekryon.gemspec
162
+ homepage: https://github.com/esotericpig/UncleKryon-server
163
+ licenses:
164
+ - GPL-3.0-or-later
165
+ metadata:
166
+ bug_tracker_uri: https://github.com/esotericpig/UncleKryon-server/issues
167
+ homepage_uri: https://github.com/esotericpig/UncleKryon-server
168
+ source_code_uri: https://github.com/esotericpig/UncleKryon-server
169
+ post_install_message: You can now use [unclekryon] on the command line.
170
+ rdoc_options: []
171
+ require_paths:
172
+ - lib
173
+ required_ruby_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: 2.4.0
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">"
181
+ - !ruby/object:Gem::Version
182
+ version: 1.3.1
183
+ requirements:
184
+ - 'Nokogiri: https://www.nokogiri.org/tutorials/installing_nokogiri.html'
185
+ rubygems_version: 3.1.2
186
+ signing_key:
187
+ specification_version: 4
188
+ summary: Uncle Kryon server (& hacker).
189
+ test_files: []