reviewer 0.1.1 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.alexignore +1 -0
  3. data/.flayignore +1 -0
  4. data/.github/workflows/main.yml +14 -4
  5. data/.gitignore +5 -0
  6. data/.inch.yml +4 -0
  7. data/.reviewer.example.yml +63 -0
  8. data/.reviewer.future.yml +221 -0
  9. data/.reviewer.yml +140 -0
  10. data/.reviewer_stdout +0 -0
  11. data/.rubocop.yml +20 -0
  12. data/CHANGELOG.md +38 -3
  13. data/Gemfile +2 -4
  14. data/Gemfile.lock +103 -20
  15. data/LICENSE.txt +4 -20
  16. data/README.md +23 -29
  17. data/Rakefile +5 -5
  18. data/bin/console +4 -4
  19. data/exe/fmt +7 -0
  20. data/exe/rvw +7 -0
  21. data/lib/reviewer/arguments/files.rb +94 -0
  22. data/lib/reviewer/arguments/keywords.rb +133 -0
  23. data/lib/reviewer/arguments/tags.rb +71 -0
  24. data/lib/reviewer/arguments.rb +54 -10
  25. data/lib/reviewer/batch.rb +91 -0
  26. data/lib/reviewer/command/string/env.rb +44 -0
  27. data/lib/reviewer/command/string/flags.rb +51 -0
  28. data/lib/reviewer/command/string.rb +66 -0
  29. data/lib/reviewer/command.rb +75 -0
  30. data/lib/reviewer/configuration.rb +32 -7
  31. data/lib/reviewer/conversions.rb +16 -0
  32. data/lib/reviewer/guidance.rb +77 -0
  33. data/lib/reviewer/history.rb +69 -0
  34. data/lib/reviewer/keywords/git/staged.rb +64 -0
  35. data/lib/reviewer/keywords/git.rb +14 -0
  36. data/lib/reviewer/keywords.rb +9 -0
  37. data/lib/reviewer/loader.rb +36 -9
  38. data/lib/reviewer/output/printer.rb +44 -0
  39. data/lib/reviewer/output/scrubber.rb +48 -0
  40. data/lib/reviewer/output/token.rb +85 -0
  41. data/lib/reviewer/output.rb +122 -0
  42. data/lib/reviewer/runner/strategies/captured.rb +157 -0
  43. data/lib/reviewer/runner/strategies/passthrough.rb +63 -0
  44. data/lib/reviewer/runner.rb +131 -0
  45. data/lib/reviewer/shell/result.rb +84 -0
  46. data/lib/reviewer/shell/timer.rb +72 -0
  47. data/lib/reviewer/shell.rb +54 -0
  48. data/lib/reviewer/tool/settings.rb +38 -19
  49. data/lib/reviewer/tool.rb +137 -23
  50. data/lib/reviewer/tools.rb +87 -8
  51. data/lib/reviewer/version.rb +1 -1
  52. data/lib/reviewer.rb +107 -28
  53. data/reviewer.gemspec +34 -19
  54. data/structure.svg +1 -0
  55. metadata +244 -12
  56. data/bin/review +0 -5
  57. data/lib/reviewer/tool/command.rb +0 -78
  58. data/lib/reviewer/tool/env.rb +0 -39
  59. data/lib/reviewer/tool/flags.rb +0 -39
  60. data/lib/reviewer/tool/verbosity.rb +0 -39
@@ -1,18 +1,97 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Provides a collection of the configured tools
4
3
  module Reviewer
5
- module Tools
6
- def self.all
7
- []
4
+ # Provides convenient access to subsets of configured tools based on provided arguments,
5
+ # configured tools, their enabled/disabled status, and more.
6
+ class Tools
7
+ include Enumerable
8
+
9
+ # Provides an instance to work with for knowing which tools to run in a given context.
10
+ # @param tags: nil [Array] the tags to use to filter tools for a run
11
+ # @param tool_names: nil [type] the explicitly provided tool names to filter tools for a run
12
+ #
13
+ # @return [Reviewer::Tools] collection of tools based on the current run context
14
+ def initialize(tags: nil, tool_names: nil)
15
+ @tags = tags
16
+ @tool_names = tool_names
17
+ end
18
+
19
+ # The current state of all available configured tools regardless of whether they are disabled
20
+ #
21
+ # @return [Hash] hash representing all of the configured tools
22
+ def to_h
23
+ configured
24
+ end
25
+ alias inspect to_h
26
+
27
+ # Provides a collection of all configured tools instantiated as Tool instances
28
+ #
29
+ # @return [Array<Tool>] the full collection of all Tool instances
30
+ def all
31
+ configured.keys.map { |tool_name| Tool.new(tool_name) }
32
+ end
33
+ alias to_a all
34
+
35
+ # Provides a collection of all enabled tools instantiated as Tool instances
36
+ #
37
+ # @return [Array<Tool>] the full collection of all enabled Tool instances
38
+ def enabled
39
+ @enabled ||= all.keep_if(&:enabled?)
40
+ end
41
+
42
+ # Provides a collection of all explicitly-specified-via-command-line tools as Tool instances
43
+ #
44
+ # @return [Array<Tool>] the full collection of explicitly-specified tools for a run
45
+ def specified
46
+ all.keep_if { |tool| named?(tool) }
47
+ end
48
+
49
+ # Provides a collection of all tagged-via-command-line tools as Tool instances
50
+ #
51
+ # @return [Array<Tool>] the full collection of tagged-via-command-line tools for a run
52
+ def tagged
53
+ enabled.keep_if { |tool| tagged?(tool) }
54
+ end
55
+
56
+ # Uses the full context of a run to provide the filtered subset of tools to use. It takes into
57
+ # consideration: tagged tools, explicitly-specified tools, configuration (enabled/disabled), and
58
+ # any other relevant details that should influence whether a specific tool should be run as part
59
+ # of the current batch being executed.
60
+ #
61
+ # @return [Array<Tool>] the full collection of should-be-used-for-this-run tools
62
+ def current
63
+ subset? ? (specified + tagged).uniq : enabled
64
+ end
65
+
66
+ private
67
+
68
+ # Determines if the current run should include a subset of a tools or the full suite of enabled
69
+ # tools by determining if any tool names or tags were provided that would reduce the full set to
70
+ # only a subset of relevant tools.
71
+ #
72
+ # @return [Boolean] true if any tool names or tags are provided via the command line
73
+ def subset?
74
+ tool_names.any? || tags.any?
75
+ end
76
+
77
+ def configured
78
+ @configured ||= Loader.configuration
79
+ end
80
+
81
+ def tags
82
+ Array(@tags || Reviewer.arguments.tags)
83
+ end
84
+
85
+ def tool_names
86
+ Array(@tool_names || Reviewer.arguments.keywords.for_tool_names)
8
87
  end
9
88
 
10
- def self.enabled
11
- []
89
+ def tagged?(tool)
90
+ tool.enabled? && (tags & tool.tags).any?
12
91
  end
13
92
 
14
- def self.disabled
15
- []
93
+ def named?(tool)
94
+ tool_names.map(&:to_s).include?(tool.key.to_s)
16
95
  end
17
96
  end
18
97
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Reviewer
4
- VERSION = "0.1.1"
4
+ VERSION = '0.1.5'
5
5
  end
data/lib/reviewer.rb CHANGED
@@ -1,42 +1,121 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "reviewer/arguments"
4
- require_relative "reviewer/configuration"
5
- require_relative "reviewer/loader"
6
- require_relative "reviewer/tool"
7
- require_relative "reviewer/tools"
8
- require_relative "reviewer/version"
3
+ require 'benchmark'
4
+ require 'forwardable'
5
+ # require 'logger'
6
+ require 'rainbow'
9
7
 
8
+ require_relative 'reviewer/conversions'
9
+
10
+ require_relative 'reviewer/arguments'
11
+ require_relative 'reviewer/batch'
12
+ require_relative 'reviewer/command'
13
+ require_relative 'reviewer/configuration'
14
+ require_relative 'reviewer/guidance'
15
+ require_relative 'reviewer/history'
16
+ require_relative 'reviewer/keywords'
17
+ require_relative 'reviewer/loader'
18
+ require_relative 'reviewer/output'
19
+ require_relative 'reviewer/runner'
20
+ require_relative 'reviewer/shell'
21
+ require_relative 'reviewer/tool'
22
+ require_relative 'reviewer/tools'
23
+ require_relative 'reviewer/version'
24
+
25
+ # Primary interface for the reviewer tools
10
26
  module Reviewer
11
27
  class Error < StandardError; end
12
28
 
13
29
  class << self
14
- attr_writer :configuration
15
- end
30
+ # Resets the loaded tools
31
+ def reset!
32
+ @tools = nil
33
+ end
16
34
 
17
- def self.review
18
- options = Arguments.new
19
- # TODO: Make it actually run the tools.
20
- puts "Running with the following options:"
21
- pp options
22
- end
35
+ # Runs the `review` command for the specified tools/files. Reviewer expects all configured
36
+ # commands that are not disabled to have an entry for the `review` command.
37
+ # @param clear_screen [boolean] clears the screen to reduce noise when true
38
+ #
39
+ # @return [void] Prints output to the console
40
+ def review(clear_screen: false)
41
+ perform(:review, clear_screen: clear_screen)
42
+ end
23
43
 
24
- def self.format
25
- options = Arguments.new
26
- # TODO: Make it actually run the tools.
27
- puts "Running with the following options:"
28
- pp options
29
- end
44
+ # Runs the `format` command for the specified tools/files for which it is configured.
45
+ # @param clear_screen [boolean] clears the screen to reduce noise when true
46
+ #
47
+ # @return [void] Prints output to the console
48
+ def format(clear_screen: false)
49
+ perform(:format, clear_screen: clear_screen)
50
+ end
30
51
 
31
- def self.configuration
32
- @configuration ||= Configuration.new
33
- end
52
+ # The collection of arguments that were passed via the command line.
53
+ #
54
+ # @return [Reviewer::Arguments] exposes tags, files, and keywords from arguments
55
+ def arguments
56
+ @arguments ||= Arguments.new
57
+ end
34
58
 
35
- def self.reset
36
- @configuration = Configuration.new
37
- end
59
+ # An interface for the collection of configured tools for accessing subsets of tools
60
+ # based on enabled/disabled, tags, keywords, etc.
61
+ #
62
+ # @return [Reviewer::Tools] exposes the set of tools to be run in a given context
63
+ def tools
64
+ @tools ||= Tools.new
65
+ end
66
+
67
+ # The primary output method for Reviewer to consistently display success/failure details for a
68
+ # unique run of each tool and the collective summary when relevant.
69
+ #
70
+ # @return [Reviewer::Output] prints formatted output to the console.
71
+ def output
72
+ @output ||= Output.new
73
+ end
74
+
75
+ # A file store for sharing information across runs
76
+ #
77
+ # @return [Reviewer::History] a YAML::Store (or Pstore) containing data on tools
78
+ def history
79
+ @history ||= History.new
80
+ end
81
+
82
+ # Exposes the configuration options for Reviewer.
83
+ #
84
+ # @return [Reviewer::Configuration] configuration settings instance
85
+ def configuration
86
+ @configuration ||= Configuration.new
87
+ end
88
+
89
+ # A block approach to configuring Reviewer.
90
+ #
91
+ # @example Set configuration file path
92
+ # Reviewer.configure do |config|
93
+ # config.file = '~/configuration.yml'
94
+ # end
95
+ #
96
+ # @return [Reviewer::Configuration] Reviewer configuration settings
97
+ def configure
98
+ yield(configuration)
99
+ end
100
+
101
+ private
102
+
103
+ # Provides a consistent approach to running and benchmarking commmands and preventing further
104
+ # execution of later tools if a command fails.
105
+ # @param command_type [Symbol] the specific command to run for each tool
106
+ # @param clear_screen [Boolean] if true, clears the screen before a run
107
+ #
108
+ # @example Run the `review` command for each relevant tool
109
+ # perform(:review)
110
+ #
111
+ # @return [Hash] the exit status (in integer format) for each command run
112
+ def perform(command_type, clear_screen: false)
113
+ output.clear if clear_screen
114
+
115
+ results = Batch.new(command_type, tools.current).run
38
116
 
39
- def self.configure
40
- yield(configuration)
117
+ # Return the largest exit status
118
+ exit results.values.max
119
+ end
41
120
  end
42
121
  end
data/reviewer.gemspec CHANGED
@@ -1,36 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/reviewer/version"
3
+ require_relative 'lib/reviewer/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "reviewer"
6
+ spec.name = 'reviewer'
7
7
  spec.version = Reviewer::VERSION
8
- spec.authors = ["Garrett Dimon"]
9
- spec.email = ["email@garrettdimon.com"]
8
+ spec.authors = ['Garrett Dimon']
9
+ spec.email = ['email@garrettdimon.com']
10
10
 
11
- spec.summary = "Provides a unified approach to managing automated code quality tools."
12
- spec.description = "Provides a unified approach to managing automated code quality tools."
13
- spec.homepage = "https://github.com/garrettdimon/reviewer"
14
- spec.license = "MIT"
15
- spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
11
+ spec.summary = 'Provides a unified approach to managing automated code quality tools.'
12
+ spec.description = 'Provides a unified approach to managing automated code quality tools.'
13
+ spec.homepage = 'https://github.com/garrettdimon/reviewer'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.9')
16
16
 
17
- spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = "https://github.com/garrettdimon/reviewer"
19
- spec.metadata["changelog_uri"] = "https://github.com/garrettdimon/reviewer/CHANGELOG.md"
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/garrettdimon/reviewer/issues'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/garrettdimon/reviewer/CHANGELOG.md'
20
+ spec.metadata['documentation_uri'] = 'https://www.rubydoc.info/gems/reviewer'
21
+ spec.metadata['source_code_uri'] = 'https://github.com/garrettdimon/reviewer'
22
+ spec.metadata['wiki_uri'] = 'https://github.com/garrettdimon/reviewer/wiki'
23
+ spec.metadata['rubygems_mfa_required'] = 'true'
20
24
 
21
25
  # Specify which files should be added to the gem when it is released.
22
26
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
27
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
28
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
25
29
  end
26
- spec.bindir = "exe"
30
+ spec.bindir = 'exe'
27
31
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
- spec.require_paths = ["lib"]
32
+ spec.require_paths = ['lib']
29
33
 
30
- # Uncomment to register a new dependency of your gem
31
- spec.add_dependency "activesupport"
32
- spec.add_dependency "slop"
34
+ spec.add_dependency 'rainbow'
35
+ spec.add_dependency 'slop'
33
36
 
34
- # For more information and examples about making a new gem, checkout our
35
- # guide at: https://bundler.io/guides/creating_gem.html
37
+ spec.add_development_dependency 'bundler-audit'
38
+ spec.add_development_dependency 'codecov'
39
+ spec.add_development_dependency 'flay'
40
+ spec.add_development_dependency 'flog'
41
+ spec.add_development_dependency 'inch'
42
+ spec.add_development_dependency 'minitest'
43
+ spec.add_development_dependency 'minitest-heat'
44
+ spec.add_development_dependency 'psych'
45
+ spec.add_development_dependency 'reek'
46
+ spec.add_development_dependency 'rubocop'
47
+ spec.add_development_dependency 'rubocop-minitest'
48
+ spec.add_development_dependency 'rubocop-rake'
49
+ spec.add_development_dependency 'simplecov'
50
+ spec.add_development_dependency 'yard'
36
51
  end
data/structure.svg ADDED
@@ -0,0 +1 @@
1
+ <svg width="1000" height="1000" style="background:white;font-family:sans-serif;overflow:visible" xmlns="http://www.w3.org/2000/svg"><defs><filter id="glow" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="4" result="coloredBlur"></feGaussianBlur><feMerge><feMergeNode in="coloredBlur"></feMergeNode><feMergeNode in="SourceGraphic"></feMergeNode></feMerge></filter></defs><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(458.1684758396736, 402.8013409019584)"><circle r="352.40190201003946" style="transition:all 0.5s ease-out" stroke="#290819" opacity="0.2" stroke-width="1" fill="none"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(520.8364435594557, 806.4990877668961)"><circle r="36.11178860447648" style="transition:all 0.5s ease-out" stroke="#290819" opacity="0.2" stroke-width="1" fill="none"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(409.6517236116371, 402.8013409019584)"><circle r="294.1473077312859" style="transition:all 0.5s ease-out" stroke="#290819" opacity="0.2" stroke-width="1" fill="none"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(757.1847045963179, 402.8013409019584)"><circle style="transition:all 0.5s ease-out" r="43.64783120267789" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#6473F2;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(687.4299657134559, 856.9423846447222)"><circle style="transition:all 0.5s ease-out" r="51.31612086796417" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(788.9846757350268, 859.3421087760426)"><circle style="transition:all 0.5s ease-out" r="46.2472197118418" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(726.4250919182904, 947.0721172937218)"><circle style="transition:all 0.5s ease-out" r="42.86782312801615" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(726.687090398783, 755.9238323654778)"><circle style="transition:all 0.5s ease-out" r="35.01102176297566" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(656.2776843121794, 774.053081197875)"><circle style="transition:all 0.5s ease-out" r="34.05582985803832" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#6473F2;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(646.3075304917123, 935.5086582680074)"><circle style="transition:all 0.5s ease-out" r="33.36112099562045" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#6473F2;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(792.4478568898579, 778.7047877445898)"><circle style="transition:all 0.5s ease-out" r="30.75334019375212" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(795.2808076405827, 932.7721040738809)"><circle style="transition:all 0.5s ease-out" r="23.450700366199015" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(628.2012046638729, 818.8498773291199)"><circle style="transition:all 0.5s ease-out" r="15.087376074028514" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(625.1052165805941, 879.58232371161)"><circle style="transition:all 0.5s ease-out" r="10.993857902246123" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(759.9605608023857, 807.5923921321375)"><circle style="transition:all 0.5s ease-out" r="9.032375950599938" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(740.4589615675088, 893.1073074759857)"><circle style="transition:all 0.5s ease-out" r="8.891894979240078" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(697.4389756167642, 792.4331053326879)"><circle style="transition:all 0.5s ease-out" r="7.7087773473446" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#FFC312;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(739.3959953779754, 800.9150363761469)"><circle style="transition:all 0.5s ease-out" r="7.6760435377025455" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(754.6373603648877, 899.7098713097646)"><circle style="transition:all 0.5s ease-out" r="2.7484644755615304" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(688.9313125250869, 914.8390531135157)"><circle style="transition:all 0.5s ease-out" r="2.5586811792341817" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(506.1084751770936, 806.4990877668961)"><circle style="transition:all 0.5s ease-out" r="16.95752838087938" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(540.0071178609526, 806.4990877668961)"><circle style="transition:all 0.5s ease-out" r="12.514822461744519" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(355.4184691733666, 395.8977440745981)"><circle style="transition:all 0.5s ease-out" r="48.297958480594644" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(453.66003516638904, 395.8977440745981)"><circle style="transition:all 0.5s ease-out" r="45.517315671192776" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(407.83945742807794, 501.6014766854548)"><circle r="65.2640503586534" style="transition:all 0.5s ease-out" stroke="#290819" opacity="0.2" stroke-width="1" fill="none"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(408.44899912286195, 266.8449117959501)"><circle r="86.7994775020254" style="transition:all 0.5s ease-out" stroke="#290819" opacity="0.2" stroke-width="1" fill="none"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(277.6542041828907, 480.50667705487933)"><circle r="62.19290440091251" style="transition:all 0.5s ease-out" stroke="#290819" opacity="0.2" stroke-width="1" fill="none"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(578.9817228671643, 482.6836693665573)"><circle r="102.49432161596253" style="transition:all 0.5s ease-out" stroke="#290819" opacity="0.2" stroke-width="1" fill="none"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(231.7281199383259, 318.8649338109235)"><circle r="92.99244862172178" style="transition:all 0.5s ease-out" stroke="#290819" opacity="0.2" stroke-width="1" fill="none"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(523.1975630378445, 335.21636724206417)"><circle style="transition:all 0.5s ease-out" r="42.347764114422745" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(176.26520220161186, 445.3500189745872)"><circle style="transition:all 0.5s ease-out" r="40.692128091001564" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(605.0441527585806, 342.75082556501854)"><circle style="transition:all 0.5s ease-out" r="35.41859767673708" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(327.59590900349434, 569.4790692623358)"><circle style="transition:all 0.5s ease-out" r="35.41148765003155" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(534.3474887230652, 253.8625225793911)"><circle style="transition:all 0.5s ease-out" r="35.34030870841474" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(476.4643386600166, 578.911911443936)"><circle style="transition:all 0.5s ease-out" r="33.68411134954049" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(299.4858839094448, 207.73782607508076)"><circle style="transition:all 0.5s ease-out" r="32.73635414382169" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(390.0098532010105, 598.7827521061267)"><circle style="transition:all 0.5s ease-out" r="29.11297292304826" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(440.3851018289799, 634.7060029474101)"><circle style="transition:all 0.5s ease-out" r="28.332745267196174" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(598.6034010548337, 275.2555582441296)"><circle style="transition:all 0.5s ease-out" r="27.956986512323546" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(502.704659203589, 194.16981738111775)"><circle style="transition:all 0.5s ease-out" r="27.79439199698623" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(266.51867408166913, 567.6833977935446)"><circle style="transition:all 0.5s ease-out" r="21.265846110817378" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(346.18721110272986, 174.45592016501854)"><circle style="transition:all 0.5s ease-out" r="20.184535485530812" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(523.0058458149439, 583.8411735366119)"><circle style="transition:all 0.5s ease-out" r="8.691407810834628" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(351.1758829983302, 609.7245028990388)"><circle style="transition:all 0.5s ease-out" r="6.806728247623728" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(383.5814103897357, 501.6014766854548)"><circle style="transition:all 0.5s ease-out" r="36.57971147907614" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(446.6323148277716, 501.6014766854548)"><circle style="transition:all 0.5s ease-out" r="22.044901117724688" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(370.84570420293034, 266.8449117959501)"><circle style="transition:all 0.5s ease-out" r="44.76989074085872" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(455.4320357843382, 266.8449117959501)"><circle style="transition:all 0.5s ease-out" r="35.39014899931409" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(265.3052220935813, 480.50667705487933)"><circle style="transition:all 0.5s ease-out" r="45.41763047036804" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(325.2849805738762, 480.50667705487933)"><circle style="transition:all 0.5s ease-out" r="10.135836168691887" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(544.5152135162864, 471.920566006636)"><circle r="61.960071361511915" style="transition:all 0.5s ease-out" stroke="#290819" opacity="0.2" stroke-width="1" fill="none"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(643.5300677882587, 471.920566006636)"><circle style="transition:all 0.5s ease-out" r="32.62849106922531" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(618.710163320952, 535.9504578797049)"><circle style="transition:all 0.5s ease-out" r="31.617298105357957" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(191.4503126965002, 309.1431465377067)"><circle style="transition:all 0.5s ease-out" r="47.13169160962506" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(281.17799339890166, 309.1431465377067)"><circle style="transition:all 0.5s ease-out" r="38.16969725154132" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(244.21679860063716, 373.9896454048579)"><circle style="transition:all 0.5s ease-out" r="32.04447135758986" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(519.6457545955952, 464.8290172745834)"><circle style="transition:all 0.5s ease-out" r="31.672997427945933" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(578.5313449242576, 464.8290172745834)"><circle style="transition:all 0.5s ease-out" r="22.78630105948141" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(556.9214342696687, 507.08309517374425)"><circle style="transition:all 0.5s ease-out" r="20.246814360728305" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(757.1847045963179, 402.8013409019584)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">reviewer.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">reviewer.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">reviewer.rb</text></g><g style="fill:#6473F2;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(687.4299657134559, 856.9423846447222)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">CODE_OF_CONDU...</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">CODE_OF_CONDU...</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">CODE_OF_CONDU...</text></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(788.9846757350268, 859.3421087760426)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">.reviewer.exa...</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">.reviewer.exa...</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">.reviewer.exa...</text></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(726.4250919182904, 947.0721172937218)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">.reviewer.yml</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">.reviewer.yml</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">.reviewer.yml</text></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(726.687090398783, 755.9238323654778)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">Gemfile.lock</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">Gemfile.lock</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">Gemfile.lock</text></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(656.2776843121794, 774.053081197875)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">reviewer.gemspec</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">reviewer.gemspec</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">reviewer.gemspec</text></g><g style="fill:#6473F2;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(646.3075304917123, 935.5086582680074)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">CHANGELOG.md</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">CHANGELOG.md</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">CHANGELOG.md</text></g><g style="fill:#6473F2;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(792.4478568898579, 778.7047877445898)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">README.md</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">README.md</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">README.md</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(355.4184691733666, 395.8977440745981)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">tool.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">tool.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">tool.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(453.66003516638904, 395.8977440745981)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">tool/settings.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">tool/settings.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">tool/settings.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(523.1975630378445, 335.21636724206417)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">command.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">command.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">command.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(176.26520220161186, 445.3500189745872)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">tools.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">tools.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">tools.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(605.0441527585806, 342.75082556501854)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">guidance.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">guidance.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">guidance.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(327.59590900349434, 569.4790692623358)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">history.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">history.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">history.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(534.3474887230652, 253.8625225793911)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">arguments.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">arguments.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">arguments.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(476.4643386600166, 578.911911443936)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">output.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">output.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">output.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(299.4858839094448, 207.73782607508076)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">runner.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">runner.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">runner.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(383.5814103897357, 501.6014766854548)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">result.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">result.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">result.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(370.84570420293034, 266.8449117959501)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">quiet.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">quiet.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">quiet.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(455.4320357843382, 266.8449117959501)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">verbose.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">verbose.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">verbose.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(265.3052220935813, 480.50667705487933)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">git/staged.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">git/staged.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">git/staged.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(643.5300677882587, 471.920566006636)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">verbosity.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">verbosity.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">verbosity.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(618.710163320952, 535.9504578797049)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">string.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">string.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">string.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(191.4503126965002, 309.1431465377067)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">keywords.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">keywords.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">keywords.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(281.17799339890166, 309.1431465377067)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">files.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">files.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">files.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(244.21679860063716, 373.9896454048579)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">tags.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">tags.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">tags.rb</text></g><g style="fill:#eb4d4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(519.6457545955952, 464.8290172745834)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">verbosity.rb</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">verbosity.rb</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">verbosity.rb</text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(458.1684758396736, 402.8013409019584)"><path fill="none" d="M 0 349.40190201003946 A 349.40190201003946 349.40190201003946 0 0 1 0 -349.40190201003946 A 349.40190201003946 349.40190201003946 0 0 1 0 349.40190201003946" id="CircleText--1" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--1" startOffset="50%">lib</textPath></text><path fill="none" d="M 0 349.40190201003946 A 349.40190201003946 349.40190201003946 0 0 1 0 -349.40190201003946 A 349.40190201003946 349.40190201003946 0 0 1 0 349.40190201003946" id="CircleText--2" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--2" startOffset="50%">lib</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(520.8364435594557, 806.4990877668961)"><path fill="none" d="M 0 33.11178860447648 A 33.11178860447648 33.11178860447648 0 0 1 0 -33.11178860447648 A 33.11178860447648 33.11178860447648 0 0 1 0 33.11178860447648" id="CircleText--3" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--3" startOffset="50%">.github/workf...</textPath></text><path fill="none" d="M 0 33.11178860447648 A 33.11178860447648 33.11178860447648 0 0 1 0 -33.11178860447648 A 33.11178860447648 33.11178860447648 0 0 1 0 33.11178860447648" id="CircleText--4" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--4" startOffset="50%">.github/workf...</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(409.6517236116371, 402.8013409019584)"><path fill="none" d="M 0 291.1473077312859 A 291.1473077312859 291.1473077312859 0 0 1 0 -291.1473077312859 A 291.1473077312859 291.1473077312859 0 0 1 0 291.1473077312859" id="CircleText--5" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--5" startOffset="50%">reviewer</textPath></text><path fill="none" d="M 0 291.1473077312859 A 291.1473077312859 291.1473077312859 0 0 1 0 -291.1473077312859 A 291.1473077312859 291.1473077312859 0 0 1 0 291.1473077312859" id="CircleText--6" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--6" startOffset="50%">reviewer</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(407.83945742807794, 501.6014766854548)"><path fill="none" d="M 0 62.26405035865341 A 62.26405035865341 62.26405035865341 0 0 1 0 -62.26405035865341 A 62.26405035865341 62.26405035865341 0 0 1 0 62.26405035865341" id="CircleText--7" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--7" startOffset="50%">shell</textPath></text><path fill="none" d="M 0 62.26405035865341 A 62.26405035865341 62.26405035865341 0 0 1 0 -62.26405035865341 A 62.26405035865341 62.26405035865341 0 0 1 0 62.26405035865341" id="CircleText--8" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--8" startOffset="50%">shell</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(408.44899912286195, 266.8449117959501)"><path fill="none" d="M 0 83.7994775020254 A 83.7994775020254 83.7994775020254 0 0 1 0 -83.7994775020254 A 83.7994775020254 83.7994775020254 0 0 1 0 83.7994775020254" id="CircleText--9" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--9" startOffset="50%">runner/strate...</textPath></text><path fill="none" d="M 0 83.7994775020254 A 83.7994775020254 83.7994775020254 0 0 1 0 -83.7994775020254 A 83.7994775020254 83.7994775020254 0 0 1 0 83.7994775020254" id="CircleText--10" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--10" startOffset="50%">runner/strate...</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(277.6542041828907, 480.50667705487933)"><path fill="none" d="M 0 59.19290440091251 A 59.19290440091251 59.19290440091251 0 0 1 0 -59.19290440091251 A 59.19290440091251 59.19290440091251 0 0 1 0 59.19290440091251" id="CircleText--11" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--11" startOffset="50%">keywords</textPath></text><path fill="none" d="M 0 59.19290440091251 A 59.19290440091251 59.19290440091251 0 0 1 0 -59.19290440091251 A 59.19290440091251 59.19290440091251 0 0 1 0 59.19290440091251" id="CircleText--12" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--12" startOffset="50%">keywords</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(578.9817228671643, 482.6836693665573)"><path fill="none" d="M 0 99.49432161596253 A 99.49432161596253 99.49432161596253 0 0 1 0 -99.49432161596253 A 99.49432161596253 99.49432161596253 0 0 1 0 99.49432161596253" id="CircleText--13" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--13" startOffset="50%">command</textPath></text><path fill="none" d="M 0 99.49432161596253 A 99.49432161596253 99.49432161596253 0 0 1 0 -99.49432161596253 A 99.49432161596253 99.49432161596253 0 0 1 0 99.49432161596253" id="CircleText--14" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--14" startOffset="50%">command</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(231.7281199383259, 318.8649338109235)"><path fill="none" d="M 0 89.99244862172178 A 89.99244862172178 89.99244862172178 0 0 1 0 -89.99244862172178 A 89.99244862172178 89.99244862172178 0 0 1 0 89.99244862172178" id="CircleText--15" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--15" startOffset="50%">arguments</textPath></text><path fill="none" d="M 0 89.99244862172178 A 89.99244862172178 89.99244862172178 0 0 1 0 -89.99244862172178 A 89.99244862172178 89.99244862172178 0 0 1 0 89.99244862172178" id="CircleText--16" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--16" startOffset="50%">arguments</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(544.5152135162864, 471.920566006636)"><path fill="none" d="M 0 58.960071361511915 A 58.960071361511915 58.960071361511915 0 0 1 0 -58.960071361511915 A 58.960071361511915 58.960071361511915 0 0 1 0 58.960071361511915" id="CircleText--17" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--17" startOffset="50%">string</textPath></text><path fill="none" d="M 0 58.960071361511915 A 58.960071361511915 58.960071361511915 0 0 1 0 -58.960071361511915 A 58.960071361511915 58.960071361511915 0 0 1 0 58.960071361511915" id="CircleText--18" transform="rotate(0)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--18" startOffset="50%">string</textPath></text></g><g transform="translate(920, 935)"><g transform="translate(0, 0)"><circle r="5" fill="#6473F2"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.md</text></g><g transform="translate(0, 15)"><circle r="5" fill="#eb4d4b"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.rb</text></g><g transform="translate(0, 30)"><circle r="5" fill="#FFC312"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.svg</text></g><div class="w-20 whitespace-nowrap text-sm text-gray-500 font-light italic">each dot sized by file size</div></g></svg>