sportdb-writers 0.1.0 → 0.1.2

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 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