judges 0.13.2 โ†’ 0.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 423404090687b2214385439c28e9d5aa3e916d3eab7fcad7b406e9c795750ed0
4
- data.tar.gz: 8f5c5b7f86625a2d57f3419010ea06891ca34ae3e1332a6858bd0f3edd467f8f
3
+ metadata.gz: 4e0f862acb1777b529b8c2547dc093020b1a345a5346677c42da550ebc0a26f3
4
+ data.tar.gz: 112b3b28257d620993031f4a647a9b2665e425249fd4de92b05100e304aec20a
5
5
  SHA512:
6
- metadata.gz: 56b32e90fb490e8664960b113b1f4aea5ff8b5be8778aab308c3d2cfdfade484d1efbe1550f523303ff8372f6065dd581ad01c19a2b48e38b4b250052ae74332
7
- data.tar.gz: '0578ac5a5a17b870e887e7ba6aaafafdaf51ad02b3d32fbb77857718b427550419e04c5d9711e907f2cb2b6eb7c35d58a0b5f4bc3ead36854fe6f5733c90bb8c'
6
+ metadata.gz: 427f79f2e3445a9bbb7ca02384ad3676f0a663cd428430ecbcf8f79f7d03496513c513960585a7a4d303a3cab756aca307d99a0209a256fb7baeb194bbd428ef
7
+ data.tar.gz: 8c38481a417786e9ddc516fa7b323433d481d827607bae63aedb47381ccb37ea9633fd5241002dd7b32abac4e6319b9fb808cee5c44f09b1a452682cf4e287d4
data/Gemfile CHANGED
@@ -24,7 +24,7 @@ source 'https://rubygems.org'
24
24
  gemspec
25
25
 
26
26
  gem 'cucumber', '9.2.0', require: false
27
- gem 'minitest', '5.24.0', require: false
27
+ gem 'minitest', '5.24.1', require: false
28
28
  gem 'net-ping', '2.0.8', require: false
29
29
  gem 'rake', '13.2.1', require: false
30
30
  gem 'rspec-rails', '6.1.3', require: false
data/Gemfile.lock CHANGED
@@ -89,7 +89,7 @@ GEM
89
89
  erubi (1.13.0)
90
90
  ethon (0.16.0)
91
91
  ffi (>= 1.15.0)
92
- factbase (0.0.54)
92
+ factbase (0.0.57)
93
93
  backtrace (~> 0.3)
94
94
  decoor (~> 0.0)
95
95
  json (~> 2.7)
@@ -119,9 +119,9 @@ GEM
119
119
  loofah (2.22.0)
120
120
  crass (~> 1.0.2)
121
121
  nokogiri (>= 1.12.0)
122
- loog (0.5.1)
122
+ loog (0.5.2)
123
123
  mini_mime (1.1.5)
124
- minitest (5.24.0)
124
+ minitest (5.24.1)
125
125
  moments (0.3.0)
126
126
  multi_test (1.1.0)
127
127
  mutex_m (0.2.0)
@@ -259,7 +259,7 @@ PLATFORMS
259
259
  DEPENDENCIES
260
260
  cucumber (= 9.2.0)
261
261
  judges!
262
- minitest (= 5.24.0)
262
+ minitest (= 5.24.1)
263
263
  net-ping (= 2.0.8)
264
264
  rake (= 13.2.1)
265
265
  rspec-rails (= 6.1.3)
data/assets/index.xsl ADDED
@@ -0,0 +1,222 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ MIT License
4
+
5
+ Copyright (c) 2024 Zerocracy
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
24
+ -->
25
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
26
+ <xsl:output method="xml" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes"/>
27
+ <xsl:param name="name"/>
28
+ <xsl:param name="date"/>
29
+ <xsl:param name="version"/>
30
+ <xsl:param name="columns"/>
31
+ <xsl:template name="javascript">
32
+ <xsl:param name="url"/>
33
+ <script type="text/javascript" src="{$url}">
34
+ <xsl:text> </xsl:text>
35
+ </script>
36
+ </xsl:template>
37
+ <xsl:template match="/">
38
+ <html>
39
+ <head>
40
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
41
+ <title>
42
+ <xsl:value-of select="$name"/>
43
+ </title>
44
+ <meta charset="UTF-8"/>
45
+ <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
46
+ <link rel="icon" href="https://www.zerocracy.com/svg/logo.svg" type="image/svg"/>
47
+ <link href="https://cdn.jsdelivr.net/gh/yegor256/tacit@gh-pages/tacit-css.min.css" rel="stylesheet"/>
48
+ <link href="https://cdn.jsdelivr.net/gh/yegor256/drops@gh-pages/drops.min.css" rel="stylesheet"/>
49
+ <xsl:call-template name="javascript">
50
+ <xsl:with-param name="url">https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js</xsl:with-param>
51
+ </xsl:call-template>
52
+ <xsl:call-template name="javascript">
53
+ <xsl:with-param name="url">https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/jquery.tablesorter.min.js</xsl:with-param>
54
+ </xsl:call-template>
55
+ <style>
56
+ * { font-family: monospace; }
57
+ section { width: 100%; }
58
+ article { border: none; }
59
+ header img { width: 3em; height: 3em; }
60
+ .sorter { cursor: pointer; }
61
+ </style>
62
+ <script type="text/javascript">
63
+ $(function() {
64
+ $("#facts").tablesorter();
65
+ });
66
+ </script>
67
+ </head>
68
+ <body>
69
+ <section>
70
+ <header>
71
+ <p>
72
+ <a href="https://www.zerocracy.com">
73
+ <img src="https://www.zerocracy.com/svg/logo.svg" alt="Zerocracy"/>
74
+ </a>
75
+ </p>
76
+ </header>
77
+ <article>
78
+ <xsl:apply-templates select="fb"/>
79
+ </article>
80
+ <footer class="smaller">
81
+ <p>
82
+ <xsl:text>The page was generated by the </xsl:text>
83
+ <a href="https://github.com/yegor256/judges">
84
+ <xsl:text>judges</xsl:text>
85
+ </a>
86
+ <xsl:text> tool (</xsl:text>
87
+ <xsl:value-of select="$version"/>
88
+ <xsl:text>) on </xsl:text>
89
+ <xsl:value-of select="$date"/>
90
+ <xsl:text>.</xsl:text>
91
+ <br/>
92
+ <a href="https://github.com/yegor256/factbase">
93
+ <xsl:text>Factbase</xsl:text>
94
+ </a>
95
+ <xsl:text>: </xsl:text>
96
+ <xsl:value-of select="count(fb/f)"/>
97
+ <xsl:text> fact</xsl:text>
98
+ <xsl:if test="count(fb/f) != 1">
99
+ <xsl:text>s</xsl:text>
100
+ </xsl:if>
101
+ <xsl:text>, </xsl:text>
102
+ <xsl:value-of select="fb/@size"/>
103
+ <xsl:text> bytes, version </xsl:text>
104
+ <xsl:value-of select="fb/@version"/>
105
+ <xsl:text>.</xsl:text>
106
+ </p>
107
+ </footer>
108
+ </section>
109
+ </body>
110
+ </html>
111
+ </xsl:template>
112
+ <xsl:template match="fb">
113
+ <table id="facts">
114
+ <thead>
115
+ <tr>
116
+ <xsl:call-template name="th">
117
+ <xsl:with-param name="cols" select="$columns"/>
118
+ </xsl:call-template>
119
+ </th>
120
+ </thead>
121
+ <tbody>
122
+ <xsl:apply-templates select="f"/>
123
+ </tbody>
124
+ </table>
125
+ </xsl:template>
126
+ <xsl:template match="f">
127
+ <tr>
128
+ <xsl:call-template name="td">
129
+ <xsl:with-param name="cols" select="$columns"/>
130
+ <xsl:with-param name="f" select="."/>
131
+ </xsl:call-template>
132
+ </tr>
133
+ </xsl:template>
134
+ <xsl:template name="th">
135
+ <xsl:param name="cols"/>
136
+ <xsl:choose>
137
+ <xsl:when test="string-length($cols) &gt; 0">
138
+ <th class="sorter">
139
+ <xsl:value-of select="substring-before(concat($cols, ','), ',')"/>
140
+ </th>
141
+ <xsl:call-template name="th">
142
+ <xsl:with-param name="cols" select="substring-after($cols, ',')"/>
143
+ </xsl:call-template>
144
+ </xsl:when>
145
+ <xsl:otherwise>
146
+ <th>
147
+ <xsl:text>&nbsp;</xsl:text>
148
+ </th>
149
+ </xsl:otherwise>
150
+ </xsl:choose>
151
+ </xsl:template>
152
+ <xsl:template name="td">
153
+ <xsl:param name="cols"/>
154
+ <xsl:param name="f"/>
155
+ <xsl:choose>
156
+ <xsl:when test="string-length($cols) &gt; 0">
157
+ <td>
158
+ <xsl:variable name="c" select="substring-before(concat($cols, ','), ',')"/>
159
+ <xsl:call-template name="value">
160
+ <xsl:with-param name="v" select="$f/*[name()=$c]"/>
161
+ </xsl:call-template>
162
+ </td>
163
+ <xsl:call-template name="td">
164
+ <xsl:with-param name="cols" select="substring-after($cols, ',')"/>
165
+ <xsl:with-param name="f" select="$f"/>
166
+ </xsl:call-template>
167
+ </xsl:when>
168
+ <xsl:otherwise>
169
+ <td>
170
+ <xsl:for-each select="$f/*">
171
+ <xsl:if test="string-length(substring-before(concat(',', $columns, ','), concat(name(), ','))) = 0">
172
+ <xsl:if test="position() &gt; 1">
173
+ <xsl:text>, </xsl:text>
174
+ </xsl:if>
175
+ <xsl:value-of select="name()"/>
176
+ <xsl:text>:</xsl:text>
177
+ <xsl:call-template name="value">
178
+ <xsl:with-param name="v" select="."/>
179
+ </xsl:call-template>
180
+ </xsl:if>
181
+ </xsl:for-each>
182
+ </td>
183
+ </xsl:otherwise>
184
+ </xsl:choose>
185
+ </xsl:template>
186
+ <xsl:template name="value">
187
+ <xsl:param name="v"/>
188
+ <xsl:choose>
189
+ <xsl:when test="$v/v">
190
+ <xsl:text>[</xsl:text>
191
+ <xsl:for-each select="$v/v">
192
+ <xsl:if test="position() &gt; 1">
193
+ <xsl:text>, </xsl:text>
194
+ </xsl:if>
195
+ <xsl:call-template name="value">
196
+ <xsl:with-param name="v" select="."/>
197
+ </xsl:call-template>
198
+ </xsl:for-each>
199
+ <xsl:text>]</xsl:text>
200
+ </xsl:when>
201
+ <xsl:otherwise>
202
+ <span>
203
+ <xsl:attribute name="style">
204
+ <xsl:text>color:</xsl:text>
205
+ <xsl:choose>
206
+ <xsl:when test="$v/@t = 'S'">
207
+ <xsl:text>#196F3D</xsl:text>
208
+ </xsl:when>
209
+ <xsl:when test="$v/@t = 'T'">
210
+ <xsl:text>#2471A3</xsl:text>
211
+ </xsl:when>
212
+ <xsl:when test="$v/@t = 'I'">
213
+ <xsl:text>#212F3C</xsl:text>
214
+ </xsl:when>
215
+ </xsl:choose>
216
+ </xsl:attribute>
217
+ <xsl:value-of select="$v"/>
218
+ </span>
219
+ </xsl:otherwise>
220
+ </xsl:choose>
221
+ </xsl:template>
222
+ </xsl:stylesheet>
data/bin/judges CHANGED
@@ -117,6 +117,8 @@ class App
117
117
  c.switch([:auto], default_value: false)
118
118
  c.desc 'Only the facts that match the expression are printed'
119
119
  c.flag([:query], default_value: '(always)')
120
+ c.desc 'Comma separated list of columns to show in HTML output (no spaces!)'
121
+ c.flag([:columns], default_value: 'when,what')
120
122
  c.desc 'Print even if target file already exists and is older than the factbase'
121
123
  c.switch([:force], default_value: false)
122
124
  c.action do |global, options, args|
@@ -8,6 +8,13 @@ Feature: Print
8
8
  Then Stdout contains "printed"
9
9
  And Exit code is zero
10
10
 
11
+ Scenario: Simple print of a small factbase, to HTML
12
+ Given I make a temp directory
13
+ Then I run bin/judges with "--verbose eval simple.fb '$fb.insert.foo = 42'"
14
+ Then I run bin/judges with "print --format=html simple.fb simple.html"
15
+ Then Stdout contains "printed"
16
+ And Exit code is zero
17
+
11
18
  Scenario: Simple print of a small factbase, to JSON
12
19
  Given I make a temp directory
13
20
  Then I run bin/judges with "--verbose eval simple.fb '$fb.insert.foo = 42'"
@@ -30,8 +30,10 @@ Feature: Test
30
30
  Given I make a temp directory
31
31
  Then I have a "myjudges/myjudge/simple_judge.rb" file with content:
32
32
  """
33
- n = $fb.insert
34
- n.foo = $foo
33
+ $valve.enter('boom') do
34
+ n = $fb.insert
35
+ n.foo = $foo
36
+ end
35
37
  """
36
38
  Then I have a "myjudges/myjudge/good.yml" file with content:
37
39
  """
@@ -19,8 +19,10 @@ Feature: Update
19
19
  Given I make a temp directory
20
20
  Then I have a "mine/judge1/simple_judge.rb" file with content:
21
21
  """
22
- n = $fb.insert
23
- n.foo = $foo
22
+ $valve.enter('boom') do
23
+ n = $fb.insert
24
+ n.foo = $foo
25
+ end
24
26
  """
25
27
  Then I have a "mylib/foo.rb" file with content:
26
28
  """
data/judges.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
27
27
  s.required_ruby_version = '>=3.2'
28
28
  s.name = 'judges'
29
- s.version = '0.13.2'
29
+ s.version = '0.14.0'
30
30
  s.license = 'MIT'
31
31
  s.summary = 'Command-Line Tool for a Factbase'
32
32
  s.description =
@@ -20,8 +20,10 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ require 'time'
23
24
  require 'fileutils'
24
25
  require 'factbase'
26
+ require 'nokogiri'
25
27
  require_relative '../../judges'
26
28
  require_relative '../../judges/impex'
27
29
  require_relative '../../judges/elapsed'
@@ -41,10 +43,11 @@ class Judges::Print
41
43
  fb = Judges::Impex.new(@loog, f).import
42
44
  fb.query("(not #{opts['query']})").delete! unless opts['query'].nil?
43
45
  o = args[1]
46
+ fmt = opts['format']&.downcase
44
47
  if o.nil?
45
- raise 'Either provide output file name or use --auto' unless opts[:auto]
48
+ raise 'Either provide output file name or use --auto' unless opts['auto']
46
49
  o = File.join(File.dirname(f), File.basename(f).gsub(/\.[^.]*$/, ''))
47
- o = "#{o}.#{opts[:format]}"
50
+ o = "#{o}.#{fmt}"
48
51
  end
49
52
  FileUtils.mkdir_p(File.dirname(o))
50
53
  if !opts['force'] && File.exist?(o)
@@ -56,7 +59,7 @@ class Judges::Print
56
59
  end
57
60
  elapsed(@loog) do
58
61
  output =
59
- case opts[:format].downcase
62
+ case fmt
60
63
  when 'yaml'
61
64
  require 'factbase/to_yaml'
62
65
  Factbase::ToYAML.new(fb).yaml
@@ -66,9 +69,30 @@ class Judges::Print
66
69
  when 'xml'
67
70
  require 'factbase/to_xml'
68
71
  Factbase::ToXML.new(fb).xml
72
+ when 'html'
73
+ to_html(opts, fb)
74
+ else
75
+ raise "Unknown format '#{fmt}'"
69
76
  end
70
77
  File.binwrite(o, output)
71
78
  throw :"Factbase printed to #{o.to_rel} (#{File.size(o)} bytes)"
72
79
  end
73
80
  end
81
+
82
+ private
83
+
84
+ def to_html(opts, fb)
85
+ xslt = Nokogiri::XSLT(File.read(File.join(__dir__, '../../../assets/index.xsl')))
86
+ require 'factbase/to_xml'
87
+ xml = Factbase::ToXML.new(fb).xml
88
+ xslt.transform(
89
+ Nokogiri::XML(xml),
90
+ Nokogiri::XSLT.quote_params(
91
+ 'name' => 'print',
92
+ 'date' => Time.now.utc.iso8601,
93
+ 'columns' => opts['columns'] || 'when,what',
94
+ 'version' => Judges::VERSION
95
+ )
96
+ )
97
+ end
74
98
  end
@@ -102,7 +102,7 @@ class Judges::Update
102
102
  elapsed(@loog) do
103
103
  c = one_judge(fb, p, global, options)
104
104
  churn += c
105
- throw :"๐Ÿ‘ The judge #{p.name} modified #{c.zero? ? 'no' : c} facts"
105
+ throw :"๐Ÿ‘ The judge #{p.name} modified #{c} facts"
106
106
  end
107
107
  rescue StandardError, SyntaxError => e
108
108
  @loog.warn(Backtrace.new(e))
data/lib/judges/judge.rb CHANGED
@@ -45,6 +45,7 @@ class Judges::Judge
45
45
  $loog = @loog
46
46
  $global = global
47
47
  $local = local
48
+ $valve = FakeValve.new if $valve.nil?
48
49
  unless @lib.nil?
49
50
  raise "Lib dir #{@lib.to_rel} is absent" unless File.exist?(@lib)
50
51
  raise "Lib #{@lib.to_rel} is not a directory" unless File.directory?(@lib)
@@ -77,4 +78,11 @@ class Judges::Judge
77
78
  def tests
78
79
  Dir.glob(File.join(@dir, '*.yml'))
79
80
  end
81
+
82
+ # Fake valve.
83
+ class FakeValve
84
+ def enter(_)
85
+ yield
86
+ end
87
+ end
80
88
  end
data/lib/judges.rb CHANGED
@@ -25,5 +25,5 @@
25
25
  # Copyright:: Copyright (c) 2024 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Judges
28
- VERSION = '0.13.2'
28
+ VERSION = '0.14.0'
29
29
  end
@@ -24,6 +24,7 @@ require 'minitest/autorun'
24
24
  require 'loog'
25
25
  require 'factbase'
26
26
  require 'yaml'
27
+ require 'securerandom'
27
28
  require_relative '../../lib/judges'
28
29
  require_relative '../../lib/judges/commands/print'
29
30
 
@@ -38,24 +39,58 @@ class TestPrint < Minitest::Test
38
39
  fb = Factbase.new
39
40
  fb.insert
40
41
  File.binwrite(f, fb.export)
41
- Judges::Print.new(Loog::NULL).run({ format: 'yaml', auto: true }, [f])
42
+ Judges::Print.new(Loog::NULL).run({ 'format' => 'yaml', 'auto' => true }, [f])
42
43
  y = File.join(d, 'base.yaml')
43
44
  assert(File.exist?(y))
44
45
  assert_equal(1, YAML.load_file(y).size)
45
46
  end
46
47
  end
47
48
 
49
+ def test_print_to_html
50
+ fb = Factbase.new
51
+ 10.times do
52
+ f = fb.insert
53
+ f.what = SecureRandom.hex(10)
54
+ f.when = Time.now
55
+ f.details = 'hey, ะดั€ัƒะณ'
56
+ f.ticket = 42
57
+ f.ticket = 55
58
+ end
59
+ Dir.mktmpdir do |d|
60
+ f = File.join(d, 'base.fb')
61
+ File.binwrite(f, fb.export)
62
+ Judges::Print.new(Loog::NULL).run(
63
+ { 'format' => 'html', 'columns' => 'what,when,ticket' },
64
+ [f, File.join(__dir__, '../../temp/base.html')]
65
+ )
66
+ end
67
+ end
68
+
69
+ def test_print_all_formats
70
+ %w[yaml html xml json].each do |fmt|
71
+ Dir.mktmpdir do |d|
72
+ f = File.join(d, 'base.fb')
73
+ fb = Factbase.new
74
+ fb.insert
75
+ File.binwrite(f, fb.export)
76
+ Judges::Print.new(Loog::NULL).run({ 'format' => fmt, 'auto' => true }, [f])
77
+ y = File.join(d, "base.#{fmt}")
78
+ assert(File.exist?(y))
79
+ end
80
+ end
81
+ end
82
+
48
83
  def test_print_twice
49
84
  Dir.mktmpdir do |d|
50
85
  f = File.join(d, 'base.fb')
51
86
  fb = Factbase.new
52
87
  fb.insert
53
88
  File.binwrite(f, fb.export)
54
- Judges::Print.new(Loog::NULL).run({ format: 'yaml', auto: true }, [f])
89
+ Judges::Print.new(Loog::NULL).run({ 'format' => 'yaml', 'auto' => true }, [f])
55
90
  y = File.join(d, 'base.yaml')
56
91
  assert(File.exist?(y))
57
92
  mtime = File.mtime(y)
58
- Judges::Print.new(Loog::NULL).run({ format: 'yaml', auto: true }, [f])
93
+ Judges::Print.new(Loog::NULL).run({ 'format' => 'yaml', 'auto' => true }, [f])
59
94
  assert_equal(mtime, File.mtime(y))
60
95
  end
61
96
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: judges
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.2
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-27 00:00:00.000000000 Z
11
+ date: 2024-07-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -209,6 +209,7 @@ files:
209
209
  - LICENSE.txt
210
210
  - README.md
211
211
  - Rakefile
212
+ - assets/index.xsl
212
213
  - bin/judges
213
214
  - features/gem_package.feature
214
215
  - features/import.feature