rufo 0.0.2 → 0.0.3

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
  SHA1:
3
- metadata.gz: 4254f11d5e797cb76d947f8e5ae0e9fddd0fc281
4
- data.tar.gz: b3937d7d503a7faf716e6deebf2f228feae26a36
3
+ metadata.gz: f651b0e7deb5c6d36cbe7632aa761954e7d49939
4
+ data.tar.gz: 20b7c26c352e682cf72547fdeebf25d31b467aa4
5
5
  SHA512:
6
- metadata.gz: 2b7110b0fc44a623f5c473b6be8b6a80bb7dede05a551a5fa8b1408f264c18281ceba1078ff991f0cda1deffa15b92369676c42254414af9ac46f3b2f3f4a07a
7
- data.tar.gz: 80d832ba0b8798af6de39fe9adeaa10c6ab0c4f09350c5b3205684e2e34b658d54cbb64f9723240833f46eaa111c44da87c165a46ab80da823e69a99be8a221d
6
+ metadata.gz: b9f40a5d0fd5ad07143ccc49fafddce8bd72cad15ada182f8cdf03b239a956f5a4072fe0df639d53a3c88d928a12058a360158b1a3b61462e073b2d9973cdfb1
7
+ data.tar.gz: 122c69242308b0999954d684ae4cfb4a0020d5ec9b68de7f76ce449a47076d659d8062f8c69fe9da80057031e07caddcc19f8a0fb653cd1e7ee0be3619d990c9
data/.rufo ADDED
@@ -0,0 +1,5 @@
1
+ align_comments true
2
+ align_assignments true
3
+ align_hash_keys true
4
+ convert_brace_to_do true
5
+ indent_size 2
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Rufo
2
2
 
3
- **Ru**by **fo**rmatter (in development)
3
+ **Ru**by **fo**rmatter
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,10 +20,61 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
+ ### Format files or directories
24
+
25
+ ```
26
+ $ rufo file names or dir names
27
+ ```
28
+
29
+ ### Format STDIN
30
+
31
+ ```
32
+ $ cat file.rb | rufo
23
33
  ```
24
- $ rufo file.rb
34
+
35
+ ### Check that no formatting changes are produced
36
+
37
+ ```
38
+ $ rufo --check file names or dir names
39
+ ```
40
+
41
+ This will print one line for each file that isn't correctly formatted
42
+ according to **rufo**, and will exit with exit code 1.
43
+
44
+ ## Editor support
45
+
46
+ - Sublime Text: [sublime-rufo](https://github.com/asterite/sublime-rufo)
47
+
48
+ ## Configuration
49
+
50
+ Rufo follows most (if not all) of the conventions found in this [Ruby style guide](https://github.com/bbatsov/ruby-style-guide). It does a bit more than that, and it can also be configured a bit.
51
+
52
+ To configure it, place a `.rufo` file in your project. When formatting a file or a directory
53
+ via the `rufo` program, a `.rufo` file will try to be found in that directory or parent directories.
54
+
55
+ The `.rufo` file is a Ruby file that is evaluated in the context of the formatter. These are the
56
+ available configurations:
57
+
58
+ ```ruby
59
+ # Whether to align successive comments (default: true)
60
+ align_comments true
61
+
62
+ # Whether to align successive assignments (default: true)
63
+ align_assignments true
64
+
65
+ # Whether to align successive hash keys (default: true)
66
+ align_hash_keys true
67
+
68
+ # Whether to convert multiline `{ ... }` block to `do ... end` (default: true)
69
+ convert_brace_to_do true
70
+
71
+ # The indent size (default: 2)
72
+ indent_size 2
25
73
  ```
26
74
 
75
+ As time passes there might be more configurations available. Please open an
76
+ issue if you need something else to be configurable.
77
+
27
78
  ## Development
28
79
 
29
80
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -2,6 +2,7 @@ require "rufo/version"
2
2
 
3
3
  module Rufo
4
4
  class Bug < Exception; end
5
+
5
6
  class SyntaxError < Exception; end
6
7
 
7
8
  def self.format(code, **options)
@@ -1,27 +1,127 @@
1
+ require "optionparser"
2
+
1
3
  module Rufo::Command
2
4
  def self.run
5
+ want_check = parse_options
6
+
3
7
  if ARGV.empty?
4
- format_stdin
8
+ format_stdin want_check
9
+ else
10
+ format_args ARGV, want_check
11
+ end
12
+ rescue Rufo::SyntaxError
13
+ STDERR.puts "Error: the given text is not a valid ruby program (it has syntax errors)"
14
+ exit 1
15
+ end
16
+
17
+ def self.format_stdin(want_check)
18
+ code = STDIN.read
19
+ result = format(code, Dir.getwd)
20
+
21
+ if want_check
22
+ exit 1 if result != code
5
23
  else
6
- format_file ARGV[0]
24
+ print result
7
25
  end
8
26
  rescue Rufo::Bug => ex
9
- STDERR.puts "You've found a bug! Please report it to https://github.com/asterite/rufo/issues with code that triggers it"
27
+ STDERR.puts "You've found a bug!"
28
+ STDERR.puts "Please report it to https://github.com/asterite/rufo/issues with code that triggers it"
29
+ STDERR.puts
30
+ raise ex
31
+ end
32
+
33
+ def self.format_args(args, want_check)
34
+ files = []
35
+
36
+ args.each do |arg|
37
+ if Dir.exist?(arg)
38
+ files.concat Dir["#{arg}/**/*.rb"]
39
+ elsif File.exist?(arg)
40
+ files << arg
41
+ else
42
+ STDERR.puts "Error: file or directory not found: #{arg}"
43
+ end
44
+ end
45
+
46
+ changed = false
47
+
48
+ files.each do |file|
49
+ changed ||= format_file file, want_check
50
+ end
51
+
52
+ exit 1 if changed
53
+ end
54
+
55
+ def self.format_file(filename, want_check)
56
+ code = File.read(filename)
57
+ result = format(code, File.dirname(filename))
58
+
59
+ if code != result
60
+ if want_check
61
+ STDERR.puts "Error: formatting #{filename} produced changes"
62
+ else
63
+ File.write(filename, result)
64
+ puts "Format: #{filename}"
65
+ end
66
+
67
+ return true
68
+ end
69
+
70
+ false
71
+ rescue Rufo::Bug => ex
72
+ STDERR.puts "You've found a bug!"
73
+ STDERR.puts "It happened while trying to format the file #{filename}"
74
+ STDERR.puts "Please report it to https://github.com/asterite/rufo/issues with code that triggers it"
10
75
  STDERR.puts
11
76
  raise ex
12
- rescue Rufo::SyntaxError
13
- STDERR.puts "Error: the given text is not a valid ruby program (it has syntax errors)"
14
77
  end
15
78
 
16
- def self.format_stdin
17
- code = STDIN.read
18
- result = Rufo.format(code)
19
- print result
79
+ def self.format(code, dir)
80
+ formatter = Rufo::Formatter.new(code)
81
+
82
+ dot_rufo = find_dot_rufo(dir)
83
+ if dot_rufo
84
+ begin
85
+ formatter.instance_eval(File.read(dot_rufo))
86
+ rescue => ex
87
+ STDERR.puts "Error evaluating #{dot_rufo}"
88
+ raise ex
89
+ end
90
+ end
91
+
92
+ formatter.format
93
+ formatter.result
20
94
  end
21
95
 
22
- def self.format_file(filename)
23
- code = File.read(filename)
24
- result = Rufo.format(code)
25
- File.write(filename, result)
96
+ def self.find_dot_rufo(dir)
97
+ dir = File.expand_path(dir)
98
+ file = File.join(dir, ".rufo")
99
+ if File.exist?(file)
100
+ return file
101
+ end
102
+
103
+ parent_dir = File.dirname(dir)
104
+ return if parent_dir == dir
105
+
106
+ find_dot_rufo(parent_dir)
107
+ end
108
+
109
+ def self.parse_options
110
+ want_check = false
111
+
112
+ OptionParser.new do |opts|
113
+ opts.banner = "Usage: rufo files or dirs [options]"
114
+
115
+ opts.on("-c", "--check", "Only check formating changes") do
116
+ want_check = true
117
+ end
118
+
119
+ opts.on("-h", "--help", "Show this help") do
120
+ puts opts
121
+ exit
122
+ end
123
+ end.parse!
124
+
125
+ want_check
26
126
  end
27
127
  end
@@ -7,36 +7,20 @@ class Rufo::Formatter
7
7
  formatter.result
8
8
  end
9
9
 
10
- # The indent size (default: 2)
11
- attr_accessor :indent_size
12
-
13
- # Whether to align successive comments (default: true)
14
- attr_accessor :align_comments
15
-
16
- # Whether to convert multiline `{ ... }` block
17
- # to `do ... end` (default: true)
18
- attr_accessor :convert_brace_to_do
19
-
20
- # Whether to align successive assignments (default: true)
21
- attr_accessor :align_assignments
22
-
23
- # Whether to align successive hash keys (default: true)
24
- attr_accessor :align_hash_keys
25
-
26
10
  def initialize(code, **options)
27
- @code = code
11
+ @code = code
28
12
  @tokens = Ripper.lex(code).reverse!
29
- @sexp = Ripper.sexp(code)
13
+ @sexp = Ripper.sexp(code)
30
14
 
31
15
  unless @sexp
32
16
  raise ::Rufo::SyntaxError.new
33
17
  end
34
18
 
35
- @indent = 0
36
- @line = 0
37
- @column = 0
19
+ @indent = 0
20
+ @line = 0
21
+ @column = 0
38
22
  @last_was_newline = false
39
- @output = ""
23
+ @output = ""
40
24
 
41
25
  # The column of a `obj.method` call, so we can align
42
26
  # calls to that dot
@@ -64,11 +48,37 @@ class Rufo::Formatter
64
48
  @hash_keys_positions = []
65
49
 
66
50
  # Settings
67
- @indent_size = options.fetch(:indent_size, 2)
68
- @align_comments = options.fetch(:align_comments, true)
51
+ @indent_size = options.fetch(:indent_size, 2)
52
+ @align_comments = options.fetch(:align_comments, true)
69
53
  @convert_brace_to_do = options.fetch(:convert_brace_to_do, true)
70
- @align_assignments = options.fetch(:align_assignments, true)
71
- @align_hash_keys = options.fetch(:align_hash_keys, true)
54
+ @align_assignments = options.fetch(:align_assignments, true)
55
+ @align_hash_keys = options.fetch(:align_hash_keys, true)
56
+ end
57
+
58
+ # The indent size (default: 2)
59
+ def indent_size(value)
60
+ @indent_size = value
61
+ end
62
+
63
+ # Whether to align successive comments (default: true)
64
+ def align_comments(value)
65
+ @align_comments = value
66
+ end
67
+
68
+ # Whether to convert multiline `{ ... }` block
69
+ # to `do ... end` (default: true)
70
+ def convert_brace_to_do(value)
71
+ @convert_brace_to_do = value
72
+ end
73
+
74
+ # Whether to align successive assignments (default: true)
75
+ def align_assignments(value)
76
+ @align_assignments = value
77
+ end
78
+
79
+ # Whether to align successive hash keys (default: true)
80
+ def align_hash_keys(value)
81
+ @align_hash_keys = value
72
82
  end
73
83
 
74
84
  def format
@@ -105,7 +115,7 @@ class Rufo::Formatter
105
115
  when :@tstring_content
106
116
  # [:@tstring_content, "hello ", [1, 1]]
107
117
  heredoc, tilde = @current_heredoc
108
- column = node[2][0]
118
+ column = node[2][0]
109
119
 
110
120
  # For heredocs with tilde we sometimes need to align the contents
111
121
  if heredoc && tilde && @last_was_newline
@@ -306,7 +316,7 @@ class Rufo::Formatter
306
316
  # Don't indent if this exp is in the same line as the previous
307
317
  # one (this happens when there's a semicolon between the exps)
308
318
  unless line_before_endline && line_before_endline == @line
309
- write_indent
319
+ write_indent
310
320
  end
311
321
  end
312
322
 
@@ -340,7 +350,7 @@ class Rufo::Formatter
340
350
  def visit_string_literal(node)
341
351
  # [:string_literal, [:string_content, exps]]
342
352
  heredoc = current_token_kind == :on_heredoc_beg
343
- tilde = current_token_value.include?("~")
353
+ tilde = current_token_value.include?("~")
344
354
 
345
355
  if heredoc
346
356
  write current_token_value.rstrip
@@ -423,7 +433,7 @@ class Rufo::Formatter
423
433
  pieces.each_with_index do |piece, i|
424
434
  visit piece
425
435
  unless last?(i, pieces)
426
- consume_op "::"
436
+ consume_op "::"
427
437
  skip_space_or_newline
428
438
  end
429
439
  end
@@ -454,7 +464,7 @@ class Rufo::Formatter
454
464
  check :on_op
455
465
 
456
466
  before = op[1][0...-1]
457
- after = op[1][-1]
467
+ after = op[1][-1]
458
468
 
459
469
  write before
460
470
  track_assignment before.size
@@ -491,6 +501,10 @@ class Rufo::Formatter
491
501
  end
492
502
  end
493
503
 
504
+ def track_comment
505
+ @comments_positions << [@line, @column, 0, nil, 0]
506
+ end
507
+
494
508
  def track_assignment(offset = 0)
495
509
  track_alignment @assignments_positions, offset
496
510
  end
@@ -607,8 +621,8 @@ class Rufo::Formatter
607
621
  def visit_call_without_receiver(node)
608
622
  # foo(arg1, ..., argN)
609
623
  #
610
- # [:method_add_arg,
611
- # [:fcall, [:@ident, "foo", [1, 0]]],
624
+ # [:method_add_arg,
625
+ # [:fcall, [:@ident, "foo", [1, 0]]],
612
626
  # [:arg_paren, [:args_add_block, [[:@int, "1", [1, 6]]], false]]]
613
627
  _, name, args = node
614
628
 
@@ -724,7 +738,7 @@ class Rufo::Formatter
724
738
  @current_heredoc = [heredoc, tilde]
725
739
  visit_string_literal_end(heredoc)
726
740
  @current_heredoc = nil
727
- printed = true
741
+ printed = true
728
742
  end
729
743
  end
730
744
 
@@ -987,7 +1001,7 @@ class Rufo::Formatter
987
1001
  end
988
1002
 
989
1003
  def visit_mlhs_paren(node)
990
- # [:mlhs_paren,
1004
+ # [:mlhs_paren,
991
1005
  # [[:mlhs_paren, [:@ident, "x", [1, 12]]]]
992
1006
  # ]
993
1007
  _, args = node
@@ -1026,7 +1040,7 @@ class Rufo::Formatter
1026
1040
  if inside_call
1027
1041
  if newline? || comment?
1028
1042
  needs_indent = true
1029
- base_column = next_indent
1043
+ base_column = next_indent
1030
1044
  consume_end_of_line
1031
1045
  write_indent(base_column)
1032
1046
  else
@@ -1431,7 +1445,7 @@ class Rufo::Formatter
1431
1445
  write_indent(next_indent)
1432
1446
  else
1433
1447
  next_token
1434
- write_space " "
1448
+ write_space " "
1435
1449
  end
1436
1450
  end
1437
1451
  end
@@ -1482,11 +1496,11 @@ class Rufo::Formatter
1482
1496
  _, key, value = node
1483
1497
 
1484
1498
  visit key
1485
-
1499
+
1486
1500
  skip_space_or_newline
1487
1501
  consume_space
1488
1502
 
1489
- track_hash_key
1503
+ track_hash_key
1490
1504
 
1491
1505
  # Don't output `=>` for keys that are `label: value`
1492
1506
  unless key[0] == :@label
@@ -1577,7 +1591,7 @@ class Rufo::Formatter
1577
1591
 
1578
1592
  if args
1579
1593
  indent(needed_indent) do
1580
- visit args
1594
+ visit args
1581
1595
  end
1582
1596
  end
1583
1597
 
@@ -1603,7 +1617,7 @@ class Rufo::Formatter
1603
1617
  end
1604
1618
 
1605
1619
  def visit_setter(node)
1606
- # foo.bar
1620
+ # foo.bar
1607
1621
  # (followed by `=`, though not included in this node)
1608
1622
  #
1609
1623
  # [:field, receiver, :".", name]
@@ -1926,7 +1940,7 @@ class Rufo::Formatter
1926
1940
  end
1927
1941
 
1928
1942
  then_keyword = keyword?("then")
1929
- inline = then_keyword || semicolon?
1943
+ inline = then_keyword || semicolon?
1930
1944
  if then_keyword
1931
1945
  next_token
1932
1946
  skip_space
@@ -1989,7 +2003,7 @@ class Rufo::Formatter
1989
2003
  def skip_space_or_newline(want_semicolon = false)
1990
2004
  found_newline = false
1991
2005
  found_comment = false
1992
- last = nil
2006
+ last = nil
1993
2007
 
1994
2008
  while true
1995
2009
  case current_token_kind
@@ -1997,7 +2011,7 @@ class Rufo::Formatter
1997
2011
  next_token
1998
2012
  when :on_nl, :on_ignored_nl
1999
2013
  next_token
2000
- last = :newline
2014
+ last = :newline
2001
2015
  found_newline = true
2002
2016
  when :on_semicolon
2003
2017
  if !found_newline && !found_comment
@@ -2017,7 +2031,7 @@ class Rufo::Formatter
2017
2031
  end
2018
2032
  next_token
2019
2033
  found_comment = true
2020
- last = :comment
2034
+ last = :comment
2021
2035
  else
2022
2036
  break
2023
2037
  end
@@ -2048,9 +2062,9 @@ class Rufo::Formatter
2048
2062
  # If the value has newlines, we need to adjust line and column
2049
2063
  number_of_lines = value.count("\n")
2050
2064
  if number_of_lines > 0
2051
- @line += number_of_lines
2052
- last_line_index = value.rindex("\n")
2053
- @column = value.size - (last_line_index + 1)
2065
+ @line += number_of_lines
2066
+ last_line_index = value.rindex("\n")
2067
+ @column = value.size - (last_line_index + 1)
2054
2068
  @last_was_newline = @column == 0
2055
2069
  end
2056
2070
  end
@@ -2074,15 +2088,15 @@ class Rufo::Formatter
2074
2088
  end
2075
2089
 
2076
2090
  # Consume and print an end of line, handling semicolons and comments
2077
- #
2091
+ #
2078
2092
  # - at_prefix: are we at a point before an expression? (if so, we don't need a space before the first comment)
2079
2093
  # - want_semicolon: do we want do print a semicolon to separate expressions?
2080
2094
  # - want_multiline: do we want multiple lines to appear, or at most one?
2081
2095
  def consume_end_of_line(at_prefix = false, want_semicolon = false, want_multiline = true)
2082
- found_newline = false # Did we find any newline during this method?
2083
- last = nil # Last token kind found
2084
- multilple_lines = false # Did we pass through more than one newline?
2085
- last_comment_has_newline = false # Does the last comment has a newline?
2096
+ found_newline = false # Did we find any newline during this method?
2097
+ last = nil # Last token kind found
2098
+ multilple_lines = false # Did we pass through more than one newline?
2099
+ last_comment_has_newline = false # Does the last comment has a newline?
2086
2100
 
2087
2101
  while true
2088
2102
  case current_token_kind
@@ -2137,13 +2151,13 @@ class Rufo::Formatter
2137
2151
  # If we didn't find any newline yet, this is the first comment,
2138
2152
  # so append a space if needed (for example after an expression)
2139
2153
  write_space " " unless at_prefix
2140
- @comments_positions << [@line, @column, @indent, nil]
2154
+ track_comment
2141
2155
  end
2142
2156
  end
2143
2157
  last_comment_has_newline = current_token_value.end_with?("\n")
2144
2158
  write current_token_value.rstrip
2145
2159
  next_token
2146
- last = :comment
2160
+ last = :comment
2147
2161
  multilple_lines = false
2148
2162
  else
2149
2163
  break
@@ -2154,17 +2168,17 @@ class Rufo::Formatter
2154
2168
  # either we didn't find a newline and we are at the end of a line (and we didn't just pass a semicolon),
2155
2169
  # or the last thing was a comment (from which we removed the newline)
2156
2170
  # or we just passed multiple lines (but printed only one)
2157
- if (!found_newline && !at_prefix && !(want_semicolon && last == :semicolon)) ||
2158
- last == :comment ||
2159
- (multilple_lines && want_multiline)
2160
- write_line
2171
+ if (!found_newline && !at_prefix && !(want_semicolon && last == :semicolon)) ||
2172
+ last == :comment ||
2173
+ (multilple_lines && want_multiline)
2174
+ write_line
2161
2175
  end
2162
2176
  end
2163
2177
 
2164
2178
  def indent(value = nil)
2165
2179
  if value
2166
2180
  old_indent = @indent
2167
- @indent = value
2181
+ @indent = value
2168
2182
  yield
2169
2183
  @indent = old_indent
2170
2184
  else
@@ -2204,7 +2218,7 @@ class Rufo::Formatter
2204
2218
  def write(value)
2205
2219
  @output << value
2206
2220
  @last_was_newline = false
2207
- @column += value.size
2221
+ @column += value.size
2208
2222
  end
2209
2223
 
2210
2224
  def write_space(value)
@@ -2215,15 +2229,15 @@ class Rufo::Formatter
2215
2229
  def write_line
2216
2230
  @output << "\n"
2217
2231
  @last_was_newline = true
2218
- @column = 0
2219
- @line += 1
2232
+ @column = 0
2233
+ @line += 1
2220
2234
  end
2221
2235
 
2222
2236
  def write_indent(indent = @indent)
2223
2237
  indent.times do
2224
2238
  @output << " "
2225
2239
  end
2226
- @column += indent
2240
+ @column += indent
2227
2241
  @last_was_newline = false
2228
2242
  end
2229
2243
 
@@ -2328,7 +2342,7 @@ class Rufo::Formatter
2328
2342
  end
2329
2343
 
2330
2344
  def push_call(call)
2331
- old_call = @current_call
2345
+ old_call = @current_call
2332
2346
  @current_call = call
2333
2347
 
2334
2348
  # A call can specify hash arguments so it acts as a
@@ -2341,7 +2355,7 @@ class Rufo::Formatter
2341
2355
  end
2342
2356
 
2343
2357
  def push_hash(node)
2344
- old_hash = @current_hash
2358
+ old_hash = @current_hash
2345
2359
  @current_hash = node
2346
2360
  yield
2347
2361
  @current_hash = old_hash
@@ -2373,18 +2387,19 @@ class Rufo::Formatter
2373
2387
  next if comments.size == 1
2374
2388
 
2375
2389
  max_column = comments.map { |l, c| c }.max
2390
+
2376
2391
  comments.each do |(line, column, _, _, offset)|
2377
2392
  next if column == max_column
2378
2393
 
2379
- split_index = column
2394
+ split_index = column
2380
2395
  split_index -= offset if offset
2381
2396
 
2382
2397
  target_line = lines[line]
2383
2398
 
2384
2399
  before = target_line[0...split_index]
2385
- after = target_line[split_index..-1]
2400
+ after = target_line[split_index..-1]
2386
2401
 
2387
- filler = " " * (max_column - column)
2402
+ filler = " " * (max_column - column)
2388
2403
  lines[line] = "#{before}#{filler}#{after}"
2389
2404
  end
2390
2405
  end
@@ -2395,4 +2410,4 @@ class Rufo::Formatter
2395
2410
  def result
2396
2411
  @output
2397
2412
  end
2398
- end
2413
+ end
@@ -1,3 +1,3 @@
1
1
  module Rufo
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ary Borenszweig
@@ -62,6 +62,7 @@ extra_rdoc_files: []
62
62
  files:
63
63
  - ".gitignore"
64
64
  - ".rspec"
65
+ - ".rufo"
65
66
  - ".travis.yml"
66
67
  - Gemfile
67
68
  - LICENSE.txt