sportdb-writers 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd53f29e4c9fc243e9a5c5ba34f0e603931317de512fd5e6c397525e49c5b773
4
- data.tar.gz: 5d1a596224394e46ec4ad8b8466e925c1a916f5aeb4bc29fba1db55cd5bb7822
3
+ metadata.gz: 7e6c426324cdb4d759fd741cc287435dc10a16f7aabbaf699295132c0f38a6e1
4
+ data.tar.gz: 70b7dc48369a7b822cd2b800dcb9dc05f1188cf18559bb43a5654d3fd63dc304
5
5
  SHA512:
6
- metadata.gz: c22afc771f1dc08681bb6a201c870b5e9688cf132a2b8d7d789fcefa1748569fdc6701e1f6b2d83f1da8c55c23bc6b7a0ba56903c2e881a65087a99f493181bb
7
- data.tar.gz: ee81dcb5964247503b0d484889b12a122416fb3d0fd8f42cb712065d75501bf1cd18715e3d4b57b202a31a0ec9f6f5624a536b45552d3a64b29e9baffd65d9db
6
+ metadata.gz: 9f78877c0169b086b0e3b8d0e5357b0b24a729a12f294a5344d7797ffe6f7be29eb0d4ed7557181429c07b959c4ddce7528bbdeb272e7e8da4396a5d037c17f0
7
+ data.tar.gz: 24502014e49eb97679ab177b893f44a375f796185155da9ee4a5e7d705d5d3e43e171b14a6c494ef3cb3087961f769fc09aa646e4e48a50cc6b426d961839789
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.1.0
1
+ ### 0.1.2
2
2
 
3
3
  ### 0.0.1 / 2020-11-15
4
4
 
data/Manifest.txt CHANGED
@@ -2,18 +2,17 @@ CHANGELOG.md
2
2
  Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
- lib/sportdb/leagues/leagues_at.rb
6
- lib/sportdb/leagues/leagues_de.rb
7
- lib/sportdb/leagues/leagues_eng.rb
8
- lib/sportdb/leagues/leagues_es.rb
9
- lib/sportdb/leagues/leagues_europe.rb
10
- lib/sportdb/leagues/leagues_it.rb
11
- lib/sportdb/leagues/leagues_mx.rb
12
- lib/sportdb/leagues/leagues_south_america.rb
13
- lib/sportdb/leagues/leagues_world.rb
5
+ bin/fbgen
6
+ bin/fbtxt
7
+ config/leagues_america.csv
8
+ config/leagues_europe.csv
9
+ config/leagues_world.csv
10
+ config/openfootball.csv
14
11
  lib/sportdb/writers.rb
15
12
  lib/sportdb/writers/github.rb
13
+ lib/sportdb/writers/github_config.rb
16
14
  lib/sportdb/writers/goals.rb
15
+ lib/sportdb/writers/league_config.rb
17
16
  lib/sportdb/writers/txt_writer.rb
18
17
  lib/sportdb/writers/version.rb
19
18
  lib/sportdb/writers/write.rb
data/Rakefile CHANGED
@@ -18,15 +18,13 @@ Hoe.spec 'sportdb-writers' do
18
18
  self.history_file = 'CHANGELOG.md'
19
19
 
20
20
  self.extra_deps = [
21
- ['sportdb-formats'], # , '>= 1.0.0'],
21
+ ['sportdb-quick'],
22
22
  ['gitti'],
23
- ['cocos'], ### fix - move upstream (incl. in sportdb-format)
24
23
  ]
25
24
 
26
25
  self.licenses = ['Public Domain']
27
26
 
28
27
  self.spec_extras = {
29
- required_ruby_version: '>= 2.2.2'
28
+ required_ruby_version: '>= 3.1.0'
30
29
  }
31
-
32
30
  end
data/bin/fbgen ADDED
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ## tip: to test run:
4
+ ## ruby -I ./lib bin/fbgen
5
+
6
+
7
+ require 'sportdb/writers'
8
+
9
+ require 'optparse'
10
+
11
+
12
+
13
+ args=ARGV
14
+
15
+
16
+ opts = {
17
+ source_path: [],
18
+ push: false,
19
+ dry: false, ## dry run (no write)
20
+ debug: true,
21
+ }
22
+
23
+
24
+
25
+ parser = OptionParser.new do |parser|
26
+ parser.banner = "Usage: #{$PROGRAM_NAME} [options] [args]"
27
+
28
+ parser.on( "-p", "--push",
29
+ "fast forward sync and commit & push changes to git repo - default is (#{opts[:push]})" ) do |push|
30
+ opts[:push] = push
31
+ end
32
+ parser.on( "--dry",
33
+ "dry run; do NOT write - default is (#{opts[:dry]})" ) do |dry|
34
+ opts[:dry] = dry
35
+ end
36
+ parser.on( "-q", "--quiet",
37
+ "less debug output/messages - default is (#{!opts[:debug]})" ) do |debug|
38
+ opts[:debug] = !debug
39
+ end
40
+ end
41
+ parser.parse!( args )
42
+
43
+
44
+
45
+ if opts[:source_path].empty? &&
46
+ File.exist?( '/sports/cache.api.fbdat') &&
47
+ File.exist?( '/sports/cache.wfb' )
48
+ opts[:source_path] << '/sports/cache.api.fbdat'
49
+ opts[:source_path] << '/sports/cache.wfb'
50
+ end
51
+
52
+
53
+ puts "OPTS:"
54
+ p opts
55
+ puts "ARGV:"
56
+ p args
57
+
58
+
59
+ ### split args in datasets with leagues and seasons
60
+ datasets = []
61
+
62
+
63
+ args.each do |arg|
64
+ if arg =~ %r{^[0-9/-]+$} ## season
65
+ if datasets.empty?
66
+ puts "!! ERROR - league required before season arg; sorry"
67
+ exit 1
68
+ end
69
+
70
+ season = Season.parse( arg ) ## check season
71
+ datasets[-1][1] << season
72
+ else ## assume league key
73
+ key = arg.downcase
74
+ league_info = Writer::LEAGUES[ key ]
75
+
76
+ if league_info.nil?
77
+ puts "!! ERROR - no league found for >#{key}<; sorry"
78
+ exit 1
79
+ end
80
+
81
+ datasets << [key, []]
82
+ end
83
+ end
84
+
85
+ pp datasets
86
+
87
+
88
+
89
+ def find_file( filename, path: )
90
+ path.each do |src_dir|
91
+ path = "#{src_dir}/#{filename}"
92
+ return path if File.exist?( path )
93
+ end
94
+
95
+ ## fix - raise file not found error!!!
96
+ nil ## not found - raise filenot found error - why? why not?
97
+ end
98
+
99
+
100
+ source_path = opts[:source_path]
101
+ source_path = ['.'] if source_path.empty? ## use ./ as default
102
+
103
+
104
+ root_dir = if opts[:push]
105
+ SportDb::GitHubSync.root # e.g. "/sports"
106
+ else
107
+ './o'
108
+ end
109
+
110
+
111
+ puts " (output) root_dir: >#{root_dir}<"
112
+
113
+
114
+ sync = if opts[:push]
115
+ repos = SportDb::GitHubSync.find_repos( datasets )
116
+ puts " #{repos.size} repo(s):"
117
+ pp repos
118
+ SportDb::GitHubSync.new( repos )
119
+ else
120
+ nil
121
+ end
122
+ puts " sync:"
123
+ pp sync
124
+
125
+ sync.git_fast_forward_if_clean if sync
126
+
127
+
128
+
129
+ datasets.each do |league_key, seasons|
130
+ seasons = [ Season('2024/25') ] if seasons.empty?
131
+
132
+ puts "==> gen #{league_key} - #{seasons.size} seasons(s)..."
133
+
134
+ league_info = Writer::LEAGUES[ league_key ]
135
+ pp league_info
136
+
137
+ seasons.each do |season|
138
+ ### get matches
139
+
140
+ filename = "#{season.to_path}/#{league_key}.csv"
141
+ path = find_file( filename, path: source_path )
142
+
143
+ if path.nil?
144
+ puts "!! no source found for #{filename}; sorry"
145
+ exit 1
146
+ end
147
+
148
+ puts " ---> reading matches in #{path} ..."
149
+ matches = SportDb::CsvMatchParser.read( path )
150
+ puts " #{matches.size} matches"
151
+
152
+ ## build
153
+ txt = SportDb::TxtMatchWriter.build( matches )
154
+ puts txt if opts[:debug]
155
+
156
+ league_name = league_info[ :name ] # e.g. Brasileiro Série A
157
+ basename = league_info[ :basename] #.e.g 1-seriea
158
+
159
+ league_name = league_name.call( season ) if league_name.is_a?( Proc ) ## is proc/func - name depends on season
160
+ basename = basename.call( season ) if basename.is_a?( Proc ) ## is proc/func - name depends on season
161
+
162
+ buf = String.new
163
+ buf << "= #{league_name} #{season}\n\n"
164
+ buf << txt
165
+
166
+ repo = SportDb::GitHubSync::REPOS[ league_key ]
167
+ repo_path = "#{repo['owner']}/#{repo['name']}"
168
+ repo_path << "/#{repo['path']}" if repo['path'] ## note: do NOT forget to add optional extra path!!!
169
+
170
+ outpath = "#{root_dir}/#{repo_path}/#{season.to_path}/#{basename}.txt"
171
+ if opts[:dry]
172
+ puts " (dry) writing to >#{outpath}<..."
173
+ else
174
+ write_text( outpath, buf )
175
+ end
176
+ end
177
+ end
178
+
179
+
180
+ sync.git_push_if_changes if sync
181
+
182
+
183
+ puts "bye"
data/bin/fbtxt ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ## tip: to test run:
4
+ ## ruby -I ./lib bin/fbtxt
5
+
6
+ # $LOAD_PATH.unshift( '../../../sportdb/sport.db/parser/lib' )
7
+ # $LOAD_PATH.unshift( '../../../sportdb/sport.db/sportdb-structs/lib' )
8
+ # $LOAD_PATH.unshift( '../../../sportdb/sport.db/quick/lib' )
9
+
10
+ require 'sportdb/writers'
11
+
12
+ require 'optparse'
13
+
14
+
15
+
16
+ args=ARGV
17
+
18
+
19
+ opts = {
20
+ }
21
+
22
+ parser = OptionParser.new do |parser|
23
+ parser.banner = "Usage: #{$PROGRAM_NAME} [options]"
24
+ end
25
+ parser.parse!( args )
26
+
27
+ puts "OPTS:"
28
+ p opts
29
+ puts "ARGV:"
30
+ p args
31
+
32
+
33
+ matches = []
34
+
35
+ ## step 1 - get all matches via csv
36
+ args.each do |arg|
37
+ path = arg
38
+ puts "==> reading matches in #{path} ..."
39
+ more_matches = SportDb::CsvMatchParser.read( path )
40
+ matches += more_matches
41
+ end
42
+
43
+ puts "#{matches.size} matches"
44
+ puts
45
+
46
+
47
+ txt = SportDb::TxtMatchWriter.build( matches )
48
+ puts txt
49
+ puts
50
+
51
+ puts "bye"
52
+
@@ -0,0 +1,6 @@
1
+ key, name, basename, start_season, end_season, comments
2
+
3
+ ar.1, Argentina Primera Division, 1-primeradivision,,,
4
+ br.1, Brasileiro Série A, 1-seriea,,,
5
+
6
+ mx.1, Liga MX, 1-ligamx,,, ## note: basename gets overwritten by stages e.g. 1-apertura or 1-clausura
@@ -0,0 +1,85 @@
1
+ key, name, basename, start_season, end_season, comments
2
+
3
+ at.1, Österr. Bundesliga, 1-bundesliga,,,
4
+ at.2, Österr. 2. Liga, 2-liga2, 2018/19,,
5
+ at.2, Österr. Erste Liga, 2-liga1, , 2017/18,
6
+ at.3.o, Österr. Regionalliga Ost, 3-regionalliga-ost,,,
7
+ at.cup, ÖFB Cup, cup,,,
8
+
9
+
10
+ de.1, Deutsche Bundesliga, 1-bundesliga,,,
11
+ de.2, Deutsche 2. Bundesliga, 2-bundesliga2,,,
12
+ de.3, Deutsche 3. Liga, 3-liga3,,,
13
+ de.cup, DFB Pokal, cup,,,
14
+
15
+ it.1, Italian Serie A, 1-seriea,,,
16
+ it.2, Italian Serie B, 2-serieb,,,
17
+
18
+ es.1, Primera División de España, 1-liga,,,
19
+ es.2, Segunda División de España, 2-liga2,,,
20
+
21
+ fr.1, French Ligue 1, 1-ligue1,,,
22
+ fr.2, French Ligue 2, 2-ligue2,,,
23
+
24
+
25
+ eng.1, English Premier League, 1-premierleague, 1992/93,,
26
+ eng.1, English Division One, 1-division1, 1892/93, 1991/92, ## start of division 1 & 2
27
+ eng.1, English Football League, 1-footballleague, 1888/89, 1891/92, ## single league (no divisions)
28
+
29
+ eng.2, English Championship, 2-championship, 2004/05,, ## rebranding divsion 1 => championship
30
+ eng.2, English Division One, 2-division1, 1992/93, 2003/04, ## start of premier league
31
+ eng.2, English Division Two, 2-division2, 1892/93, 1991/92, ## or use English Football League Second Division ???
32
+
33
+ eng.3, English League One, 3-league1,,,
34
+ eng.4, English League Two, 4-league2,,,
35
+ eng.5, English National League, 5-nationalleague,,,
36
+ eng.cup, English FA Cup, facup,,,
37
+
38
+
39
+ hu.1, Hungarian NB I, 1-nbi,,,
40
+
41
+ gr.1, Super League Greece, 1-superleague,,,
42
+
43
+ pt.1, Portuguese Primeira Liga, 1-primeiraliga,,,
44
+ pt.2, Portuguese Segunda Liga, 2-segundaliga,,,
45
+
46
+ ch.1, Swiss Super League, 1-superleague,,,
47
+ ch.2, Swiss Challenge League, 2-challengeleague,,,
48
+
49
+ tr.1, Turkish Süper Lig, 1-superlig,,,
50
+ tr.2, Turkish 1. Lig, 2-lig1,,,
51
+
52
+ is.1, Iceland Urvalsdeild, 1-urvalsdeild,,,
53
+
54
+ sco.1, Scottish Premiership, 1-premiership,,,
55
+
56
+ ie.1, Irish Premier Division, 1-premierdivision,,,
57
+
58
+ fi.1, Finland Veikkausliiga, 1-veikkausliiga,,,
59
+
60
+ se.1, Sweden Allsvenskan, 1-allsvenskan,,,
61
+ se.2, Sweden Superettan, 2-superettan,,,
62
+
63
+ no.1, Norwegian Eliteserien, 1-eliteserien,,,
64
+ dk.1, Denmark Superligaen, 1-superligaen,,,
65
+
66
+ lu.1, Luxembourger First Division, 1-nationaldivision,,,
67
+
68
+ be.1, Belgian First Division A, 1-firstdivisiona,,,
69
+
70
+ nl.1, Dutch Eredivisie, 1-eredivisie,,,
71
+
72
+ cz.1, Czech First League, 1-firstleague,,,
73
+ sk.1, Slovakia First League, 1-superliga,,,
74
+ hr.1, Croatia 1. HNL, 1-hnl,,,
75
+
76
+ pl.1, Poland Ekstraklasa, 1-ekstraklasa,,,
77
+
78
+ ro.1, Romanian Liga 1, 1-liga1,,,
79
+
80
+ ua.1, Ukraine Premier League, 1-premierleague,,,
81
+
82
+ ru.1, Russian Premier League, 1-premierliga,,,
83
+ ru.2, Russian 1. Division, 2-division1,,,
84
+
85
+
@@ -0,0 +1,4 @@
1
+ key, name, basename, start_season, end_season, comments
2
+
3
+ cn.1, Chinese Super League, 1-superleague,,,
4
+ jp.1, Japan J1 League, 1-j1league,,,
@@ -0,0 +1,52 @@
1
+ key, path
2
+
3
+ at, austria
4
+
5
+ de, deutschland
6
+ eng, england
7
+ es, espana
8
+ it, italy
9
+
10
+ fr, europe/france
11
+
12
+ hu, europe/hungary
13
+ gr, europe/greece
14
+ pt, europe/portugal
15
+
16
+ ch, europe/switzerland
17
+
18
+ tr, europe/turkey
19
+
20
+ is, europe/iceland
21
+ sco, europe/scotland
22
+ ie, europe/ireland
23
+
24
+ fi, europe/finland
25
+ se, europe/sweden
26
+ no, europe/norway
27
+ dk, europe/denmark
28
+
29
+ lu, europe/luxembourg
30
+ be, europe/belgium
31
+ nl, europe/netherlands
32
+ cz, europe/czech-republic
33
+
34
+ sk, europe/slovakia
35
+ hr, europe/croatia
36
+ pl, europe/poland
37
+
38
+ ro, europe/romania
39
+
40
+ ua, europe/ukraine
41
+
42
+ ru, europe/russia
43
+
44
+
45
+ mx, mexico
46
+
47
+ ar, south-america/argentina
48
+ br, south-america/brazil
49
+
50
+ cn, world/asia/china
51
+ jp, world/asia/japan
52
+
@@ -6,118 +6,47 @@ module SportDb
6
6
  ## add -i/--interactive flag
7
7
  ## will prompt yes/no before git operations (with consequences)!!!
8
8
 
9
+
10
+
9
11
  class GitHubSync
10
12
 
11
- ## map leagues to repo+path
12
- ## e.g. fr.1 => europe/france
13
- ## eng..1 => england
14
- REPOS = {
15
- 'at.1' => 'austria',
16
- 'at.2' => 'austria',
17
- 'at.3.o' => 'austria',
18
- 'at.cup' => 'austria',
19
-
20
- 'de.1' => 'deutschland',
21
- 'de.2' => 'deutschland',
22
- 'de.3' => 'deutschland',
23
- 'de.cup' => 'deutschland',
24
-
25
- 'eng.1' => 'england',
26
- 'eng.2' => 'england',
27
- 'eng.3' => 'england',
28
- 'eng.4' => 'england',
29
- 'eng.5' => 'england',
30
- 'eng.cup' => 'england', # English FA Cup
31
-
32
- 'es.1' => 'espana',
33
- 'es.2' => 'espana',
34
-
35
- 'fr.1' => 'europe/france',
36
- 'fr.2' => 'europe/france',
37
-
38
- 'hu.1' => 'europe/hungary',
39
- 'gr.1' => 'europe/greece',
40
- 'pt.1' => 'europe/portugal',
41
- 'pt.2' => 'europe/portugal',
42
-
43
- 'ch.1' => 'europe/switzerland',
44
- 'ch.2' => 'europe/switzerland',
45
-
46
- 'tr.1' => 'europe/turkey',
47
- 'tr.2' => 'europe/turkey',
48
-
49
- 'is.1' => 'europe/iceland',
50
- 'sco.1' => 'europe/scotland',
51
- 'ie.1' => 'europe/ireland',
52
-
53
- 'fi.1' => 'europe/finland',
54
- 'se.1' => 'europe/sweden',
55
- 'se.2' => 'europe/sweden',
56
- 'no.1' => 'europe/norway',
57
- 'dk.1' => 'europe/denmark',
58
-
59
- 'lu.1' => 'europe/luxembourg',
60
- 'be.1' => 'europe/belgium',
61
- 'nl.1' => 'europe/netherlands',
62
- 'cz.1' => 'europe/czech-republic',
63
-
64
- 'sk.1' => 'europe/slovakia',
65
- 'hr.1' => 'europe/croatia',
66
- 'pl.1' => 'europe/poland',
67
-
68
- 'ro.1' => 'europe/romania',
69
-
70
- 'ua.1' => 'europe/ukraine',
71
-
72
- 'ru.1' => 'europe/russia',
73
- 'ru.2' => 'europe/russia',
74
-
75
- 'it.1' => 'italy',
76
- 'it.2' => 'italy',
77
-
78
- 'mx.1' => 'mexico',
79
-
80
- 'ar.1' => 'south-america/argentina',
81
- 'br.1' => 'south-america/brazil',
82
-
83
- 'cn.1' => 'world/asia/china',
84
- 'jp.1' => 'world/asia/japan',
85
- }
86
-
87
-
88
-
89
- ########
13
+ ########
90
14
  ## (auto)default to Writer.config.out_dir - why? why not?
91
15
  ##
92
- ## note - is root for org (NOT monotree for now - why?`why not?)
93
- def self.root() @root || "/sports/openfootball"; end
94
- def self.root=( dir ) @root = dir; end
16
+ ## note - is monotree (that is, requires openfootball/england etc.
17
+ ## for repo pathspecs)
18
+ def self.root() @root || "/sports"; end
19
+ def self.root=( dir ) @root = dir; end
95
20
  ## use root_dir (alias) - why? why not?
96
21
 
97
22
 
98
- def initialize( datasets )
99
- @repos = _find_repos( datasets )
23
+ def initialize( repos )
24
+ @repos = repos
100
25
  end
101
26
 
102
27
 
103
- def git_push_if_changes
104
- _git_push_if_changes( @repos )
105
- end
106
-
28
+ def git_push_if_changes
29
+ message = "auto-update week #{Date.today.cweek}" ## add /#{Date.today.cday - why? why not?
30
+ puts message
31
+
32
+ @repos.each do |pathspec|
33
+ _git_push_if_changes( pathspec, message: message )
34
+ end
35
+ end
36
+
107
37
  def git_fast_forward_if_clean
108
- _git_fast_forward_if_clean( @repos )
38
+ @repos.each do |pathspec|
39
+ _git_fast_forward_if_clean( pathspec )
40
+ end
109
41
  end
110
42
 
111
43
 
44
+
112
45
  ## todo/fix: rename to something like
113
46
  ## git_(auto_)commit_and_push_if_changes/if_dirty()
114
47
 
115
- def _git_push_if_changes( names ) ## optenfootball repo names e.g. world, england, etc.
116
- message = "auto-update week #{Date.today.cweek}" ## add /#{Date.today.cday - why? why not?
117
- puts message
118
-
119
- names.each do |name|
120
- path = "#{self.class.root}/#{name}"
48
+ def _git_push_if_changes( pathspec, message: )
49
+ path = "#{self.class.root}/#{pathspec}"
121
50
 
122
51
  Gitti::GitProject.open( path ) do |proj|
123
52
  puts ''
@@ -133,13 +62,11 @@ def _git_push_if_changes( names ) ## optenfootball repo names e.g. world, engl
133
62
  proj.push
134
63
  end
135
64
  end
136
- end
137
65
  end
138
66
 
139
67
 
140
- def _git_fast_forward_if_clean( names )
141
- names.each do |name|
142
- path = "#{self.class.root}/#{name}"
68
+ def _git_fast_forward_if_clean( pathspec )
69
+ path = "#{self.class.root}/#{pathspec}"
143
70
 
144
71
  Gitti::GitProject.open( path ) do |proj|
145
72
  output = proj.changes
@@ -151,45 +78,6 @@ def _git_fast_forward_if_clean( names )
151
78
 
152
79
  proj.fast_forward
153
80
  end
154
- end
155
81
  end
156
-
157
-
158
- ## todo/check: find a better name for helper?
159
- ## note: datasets of format
160
- ##
161
- ## DATASETS = [
162
- ## ['it.1', %w[2020/21 2019/20]],
163
- ## ['it.2', %w[2019/20]],
164
- ## ['es.1', %w[2019/20]],
165
- ## ['es.2', %w[2019/20]],
166
- ## ]
167
-
168
-
169
- def _find_repos( datasets )
170
- repos = []
171
- datasets.each do |dataset|
172
- league_key = dataset[0]
173
- path = REPOS[ league_key ]
174
- ## pp path
175
- if path.nil?
176
- puts "!! ERROR - no repo path found for league >#{league_key}<; sorry"
177
- exit 1
178
- end
179
-
180
- ## auto-add
181
- ## openfootball/ org here
182
- ## and keep root "generic" to monoroot - why? why not?
183
-
184
- ## use only first part e.g. europe/belgium => europe
185
- repos << path.split( '/' )[0]
186
- end
187
- pp repos
188
- repos.uniq ## note: remove duplicates (e.g. europe or world or such)
189
- end
190
-
191
-
192
-
193
-
194
82
  end # class GitHub
195
83
  end # module SportDb