fig 0.1.73 → 0.1.75

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.
Files changed (50) hide show
  1. data/Changes +75 -0
  2. data/lib/fig.rb +1 -1
  3. data/lib/fig/command.rb +36 -12
  4. data/lib/fig/command/action.rb +1 -1
  5. data/lib/fig/command/action/dump_package_definition_parsed.rb +4 -6
  6. data/lib/fig/command/action/run_command_statement.rb +3 -2
  7. data/lib/fig/command/options.rb +12 -3
  8. data/lib/fig/command/options/parser.rb +2 -0
  9. data/lib/fig/command/package_loader.rb +1 -0
  10. data/lib/fig/config_file_error.rb +1 -1
  11. data/lib/fig/grammar/base.rb +214 -0
  12. data/lib/fig/grammar/base.treetop +29 -0
  13. data/lib/fig/grammar/v0.rb +1493 -0
  14. data/lib/fig/grammar/v0.treetop +167 -0
  15. data/lib/fig/grammar/v1.rb +1478 -0
  16. data/lib/fig/grammar/v1.treetop +174 -0
  17. data/lib/fig/grammar/version.rb +144 -0
  18. data/lib/fig/grammar/version.treetop +22 -0
  19. data/lib/fig/grammar/version_identification.rb +113 -0
  20. data/lib/fig/grammar/version_identification.treetop +27 -0
  21. data/lib/fig/log4r_config_error.rb +1 -1
  22. data/lib/fig/no_such_package_config_error.rb +1 -1
  23. data/lib/fig/not_found_error.rb +7 -0
  24. data/lib/fig/operating_system.rb +31 -20
  25. data/lib/fig/package.rb +8 -3
  26. data/lib/fig/package_definition_text_assembler.rb +88 -0
  27. data/lib/fig/package_descriptor_parse_error.rb +1 -1
  28. data/lib/fig/parser.rb +115 -29
  29. data/lib/fig/parser_package_build_state.rb +38 -11
  30. data/lib/fig/repository.rb +5 -8
  31. data/lib/fig/repository_package_publisher.rb +114 -96
  32. data/lib/fig/runtime_environment.rb +42 -14
  33. data/lib/fig/statement.rb +133 -0
  34. data/lib/fig/statement/archive.rb +6 -4
  35. data/lib/fig/statement/asset.rb +28 -34
  36. data/lib/fig/statement/command.rb +6 -2
  37. data/lib/fig/statement/configuration.rb +4 -12
  38. data/lib/fig/statement/grammar_version.rb +22 -0
  39. data/lib/fig/statement/include.rb +5 -6
  40. data/lib/fig/statement/override.rb +6 -3
  41. data/lib/fig/statement/path.rb +12 -2
  42. data/lib/fig/statement/resource.rb +8 -8
  43. data/lib/fig/statement/retrieve.rb +11 -3
  44. data/lib/fig/statement/set.rb +12 -2
  45. data/lib/fig/unparser.rb +127 -0
  46. data/lib/fig/unparser/v0.rb +84 -0
  47. data/lib/fig/unparser/v1.rb +77 -0
  48. data/lib/fig/url.rb +7 -0
  49. metadata +139 -25
  50. data/lib/fig/grammar.treetop +0 -147
@@ -0,0 +1,167 @@
1
+ # Treetop (http://treetop.rubyforge.org/) grammar for package definitions from
2
+ # the early days.
3
+
4
+ # Some aspects of this grammar are significantly dumber than they could be
5
+ # because:
6
+ #
7
+ # * We want to treat statements as identically as possible to their
8
+ # command-line equivalents.
9
+ # * Treetop parse errors are pretty inscrutable at times and we can make
10
+ # error messages clearer by validating a lot of the terminals ourselves.
11
+
12
+ require 'treetop'
13
+
14
+ require 'fig/grammar/base'
15
+ require 'fig/grammar/version'
16
+
17
+ module Fig
18
+ module Grammar
19
+ grammar V0
20
+ include Fig::Grammar::Base
21
+ include Fig::Grammar::Version
22
+
23
+ rule package
24
+ optional_ws grammar_version:grammar_version? ws* statements:(package_statement*) optional_ws {
25
+ def to_package(directory, build_state)
26
+ return build_state.new_package_statement(
27
+ directory, grammar_version, statements
28
+ )
29
+ end
30
+ }
31
+ end
32
+
33
+ rule package_statement
34
+ archive / resource / retrieve / config
35
+ end
36
+
37
+ rule archive
38
+ statement_start:'archive' ws+ url:asset_url {
39
+ def to_package_statement(build_state)
40
+ return build_state.new_asset_statement(
41
+ Statement::Archive, statement_start, url.url
42
+ )
43
+ end
44
+ }
45
+ end
46
+
47
+ rule resource
48
+ statement_start:'resource' ws+ url:asset_url {
49
+ def to_package_statement(build_state)
50
+ return build_state.new_asset_statement(
51
+ Statement::Resource, statement_start, url.url
52
+ )
53
+ end
54
+ }
55
+ end
56
+
57
+ rule asset_url
58
+ # Unquoted allows globbing for files, quoted does not.
59
+ #
60
+ # Unquoted, anything but:
61
+ # @ - To allow for package substitution
62
+ # ' - Future expansion
63
+ # "<>| - Characters not allowed in filenames on Windows
64
+ # \s - Necessary for the "ws" token to work
65
+ (url:[^@'"<>|\s]+ ws)
66
+
67
+ # Quoted, anything but:
68
+ # @ - To allow for package substitution
69
+ # ' - Future expansion
70
+ # "<>| - Characters not allowed in filenames on Windows
71
+ # *?\[\]{} - Characters significant to Dir.glob()
72
+ # \s - We just don't want these. :] (May need to allow space.)
73
+ / ('"' url:[^@'"<>|*?\[\]{}\s]+ '"' ws)
74
+ end
75
+
76
+ rule retrieve
77
+ statement_start:'retrieve' ws+ var:environment_variable_name '->' path:retrieve_path ws+ {
78
+ def to_package_statement(build_state)
79
+ return build_state.new_retrieve_statement(statement_start, var, path)
80
+ end
81
+ }
82
+ end
83
+
84
+ rule retrieve_path
85
+ [a-zA-Z0-9_/.\[\]-]+
86
+ end
87
+
88
+ rule config
89
+ statement_start:'config' ws+ config_name ws+ statements:config_statement* 'end' ws+ {
90
+ def to_package_statement(build_state)
91
+ return build_state.new_configuration_statement(
92
+ statement_start, config_name, statements
93
+ )
94
+ end
95
+ }
96
+ end
97
+
98
+ rule config_name
99
+ [a-zA-Z0-9_.-]+
100
+ end
101
+
102
+ rule config_statement
103
+ override / include / command / path / set
104
+ end
105
+
106
+ rule include
107
+ statement_start:'include' ws+ descriptor_string ws+ {
108
+ def to_config_statement(build_state)
109
+ return build_state.new_include_statement(
110
+ statement_start, descriptor_string
111
+ )
112
+ end
113
+ }
114
+ end
115
+
116
+ rule override
117
+ statement_start:'override' ws+ descriptor_string ws+ {
118
+ def to_config_statement(build_state)
119
+ return build_state.new_override_statement(
120
+ statement_start, descriptor_string
121
+ )
122
+ end
123
+ }
124
+ end
125
+
126
+ rule path
127
+ statement_start:('add' / 'append' / 'path') ws+ name_value:[\S]+ ws+ {
128
+ def to_config_statement(build_state)
129
+ return build_state.new_environment_variable_statement(
130
+ Statement::Path, statement_start, name_value
131
+ )
132
+ end
133
+ }
134
+ end
135
+
136
+ rule environment_variable_name
137
+ [a-zA-Z0-9_]+
138
+ end
139
+
140
+ rule set
141
+ statement_start:'set' ws+ name_value:[\S]+ ws+ {
142
+ def to_config_statement(build_state)
143
+ return build_state.new_environment_variable_statement(
144
+ Statement::Set, statement_start, name_value
145
+ )
146
+ end
147
+ }
148
+ end
149
+
150
+ rule command
151
+ statement_start:'command' ws+ string ws+ {
152
+ def to_config_statement(build_state)
153
+ return build_state.new_command_statement(statement_start, string)
154
+ end
155
+ }
156
+ end
157
+
158
+ rule string
159
+ '"' value:[^"]* '"'
160
+ end
161
+
162
+ rule descriptor_string
163
+ [\S]+
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,1478 @@
1
+ # Autogenerated from a Treetop grammar. Edits may be lost.
2
+
3
+
4
+ # Treetop (http://treetop.rubyforge.org/) grammar for package definitions in v1
5
+ # format.
6
+
7
+ # Some aspects of this grammar are significantly dumber than they could be
8
+ # because:
9
+ #
10
+ # * We want to treat statements as identically as possible to their
11
+ # command-line equivalents.
12
+ # * Treetop parse errors are pretty inscrutable at times and we can make
13
+ # error messages clearer by validating a lot of the terminals ourselves.
14
+
15
+ require 'treetop'
16
+
17
+ require 'fig/grammar/base'
18
+ require 'fig/grammar/version'
19
+
20
+ module Fig
21
+ module Grammar
22
+ module V1
23
+ include Treetop::Runtime
24
+
25
+ def root
26
+ @root ||= :package
27
+ end
28
+
29
+ include Fig::Grammar::Base
30
+
31
+ include Fig::Grammar::Version
32
+
33
+ module Package0
34
+ def optional_ws_or_comment1
35
+ elements[0]
36
+ end
37
+
38
+ def grammar_version
39
+ elements[1]
40
+ end
41
+
42
+ def statements
43
+ elements[2]
44
+ end
45
+
46
+ def optional_ws_or_comment2
47
+ elements[3]
48
+ end
49
+ end
50
+
51
+ module Package1
52
+ def to_package(directory, build_state)
53
+ return build_state.new_package_statement(
54
+ directory, grammar_version, statements
55
+ )
56
+ end
57
+ end
58
+
59
+ def _nt_package
60
+ start_index = index
61
+ if node_cache[:package].has_key?(index)
62
+ cached = node_cache[:package][index]
63
+ if cached
64
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
65
+ @index = cached.interval.end
66
+ end
67
+ return cached
68
+ end
69
+
70
+ i0, s0 = index, []
71
+ r1 = _nt_optional_ws_or_comment
72
+ s0 << r1
73
+ if r1
74
+ r3 = _nt_grammar_version
75
+ if r3
76
+ r2 = r3
77
+ else
78
+ r2 = instantiate_node(SyntaxNode,input, index...index)
79
+ end
80
+ s0 << r2
81
+ if r2
82
+ s4, i4 = [], index
83
+ loop do
84
+ r5 = _nt_package_statement_with_ws
85
+ if r5
86
+ s4 << r5
87
+ else
88
+ break
89
+ end
90
+ end
91
+ r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
92
+ s0 << r4
93
+ if r4
94
+ r6 = _nt_optional_ws_or_comment
95
+ s0 << r6
96
+ end
97
+ end
98
+ end
99
+ if s0.last
100
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
101
+ r0.extend(Package0)
102
+ r0.extend(Package1)
103
+ else
104
+ @index = i0
105
+ r0 = nil
106
+ end
107
+
108
+ node_cache[:package][start_index] = r0
109
+
110
+ r0
111
+ end
112
+
113
+ module PackageStatementWithWs0
114
+ def package_statement
115
+ elements[0]
116
+ end
117
+
118
+ end
119
+
120
+ module PackageStatementWithWs1
121
+ def to_package_statement(build_state)
122
+ return package_statement.to_package_statement(build_state)
123
+ end
124
+ end
125
+
126
+ def _nt_package_statement_with_ws
127
+ start_index = index
128
+ if node_cache[:package_statement_with_ws].has_key?(index)
129
+ cached = node_cache[:package_statement_with_ws][index]
130
+ if cached
131
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
132
+ @index = cached.interval.end
133
+ end
134
+ return cached
135
+ end
136
+
137
+ i0, s0 = index, []
138
+ r1 = _nt_package_statement
139
+ s0 << r1
140
+ if r1
141
+ s2, i2 = [], index
142
+ loop do
143
+ r3 = _nt_ws_or_comment
144
+ if r3
145
+ s2 << r3
146
+ else
147
+ break
148
+ end
149
+ end
150
+ if s2.empty?
151
+ @index = i2
152
+ r2 = nil
153
+ else
154
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
155
+ end
156
+ s0 << r2
157
+ end
158
+ if s0.last
159
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
160
+ r0.extend(PackageStatementWithWs0)
161
+ r0.extend(PackageStatementWithWs1)
162
+ else
163
+ @index = i0
164
+ r0 = nil
165
+ end
166
+
167
+ node_cache[:package_statement_with_ws][start_index] = r0
168
+
169
+ r0
170
+ end
171
+
172
+ def _nt_package_statement
173
+ start_index = index
174
+ if node_cache[:package_statement].has_key?(index)
175
+ cached = node_cache[:package_statement][index]
176
+ if cached
177
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
178
+ @index = cached.interval.end
179
+ end
180
+ return cached
181
+ end
182
+
183
+ i0 = index
184
+ r1 = _nt_archive
185
+ if r1
186
+ r0 = r1
187
+ else
188
+ r2 = _nt_resource
189
+ if r2
190
+ r0 = r2
191
+ else
192
+ r3 = _nt_retrieve
193
+ if r3
194
+ r0 = r3
195
+ else
196
+ r4 = _nt_config
197
+ if r4
198
+ r0 = r4
199
+ else
200
+ @index = i0
201
+ r0 = nil
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ node_cache[:package_statement][start_index] = r0
208
+
209
+ r0
210
+ end
211
+
212
+ module Archive0
213
+ def statement_start
214
+ elements[0]
215
+ end
216
+
217
+ def url
218
+ elements[2]
219
+ end
220
+ end
221
+
222
+ module Archive1
223
+ def to_package_statement(build_state)
224
+ return build_state.new_asset_statement(
225
+ Statement::Archive, statement_start, url
226
+ )
227
+ end
228
+ end
229
+
230
+ def _nt_archive
231
+ start_index = index
232
+ if node_cache[:archive].has_key?(index)
233
+ cached = node_cache[:archive][index]
234
+ if cached
235
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
236
+ @index = cached.interval.end
237
+ end
238
+ return cached
239
+ end
240
+
241
+ i0, s0 = index, []
242
+ if has_terminal?('archive', false, index)
243
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 7))
244
+ @index += 7
245
+ else
246
+ terminal_parse_failure('archive')
247
+ r1 = nil
248
+ end
249
+ s0 << r1
250
+ if r1
251
+ s2, i2 = [], index
252
+ loop do
253
+ r3 = _nt_ws_or_comment
254
+ if r3
255
+ s2 << r3
256
+ else
257
+ break
258
+ end
259
+ end
260
+ if s2.empty?
261
+ @index = i2
262
+ r2 = nil
263
+ else
264
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
265
+ end
266
+ s0 << r2
267
+ if r2
268
+ r4 = _nt_asset_url
269
+ s0 << r4
270
+ end
271
+ end
272
+ if s0.last
273
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
274
+ r0.extend(Archive0)
275
+ r0.extend(Archive1)
276
+ else
277
+ @index = i0
278
+ r0 = nil
279
+ end
280
+
281
+ node_cache[:archive][start_index] = r0
282
+
283
+ r0
284
+ end
285
+
286
+ module Resource0
287
+ def statement_start
288
+ elements[0]
289
+ end
290
+
291
+ def url
292
+ elements[2]
293
+ end
294
+ end
295
+
296
+ module Resource1
297
+ def to_package_statement(build_state)
298
+ return build_state.new_asset_statement(
299
+ Statement::Resource, statement_start, url
300
+ )
301
+ end
302
+ end
303
+
304
+ def _nt_resource
305
+ start_index = index
306
+ if node_cache[:resource].has_key?(index)
307
+ cached = node_cache[:resource][index]
308
+ if cached
309
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
310
+ @index = cached.interval.end
311
+ end
312
+ return cached
313
+ end
314
+
315
+ i0, s0 = index, []
316
+ if has_terminal?('resource', false, index)
317
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 8))
318
+ @index += 8
319
+ else
320
+ terminal_parse_failure('resource')
321
+ r1 = nil
322
+ end
323
+ s0 << r1
324
+ if r1
325
+ s2, i2 = [], index
326
+ loop do
327
+ r3 = _nt_ws_or_comment
328
+ if r3
329
+ s2 << r3
330
+ else
331
+ break
332
+ end
333
+ end
334
+ if s2.empty?
335
+ @index = i2
336
+ r2 = nil
337
+ else
338
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
339
+ end
340
+ s0 << r2
341
+ if r2
342
+ r4 = _nt_asset_url
343
+ s0 << r4
344
+ end
345
+ end
346
+ if s0.last
347
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
348
+ r0.extend(Resource0)
349
+ r0.extend(Resource1)
350
+ else
351
+ @index = i0
352
+ r0 = nil
353
+ end
354
+
355
+ node_cache[:resource][start_index] = r0
356
+
357
+ r0
358
+ end
359
+
360
+ module AssetUrl0
361
+ end
362
+
363
+ module AssetUrl1
364
+ end
365
+
366
+ def _nt_asset_url
367
+ start_index = index
368
+ if node_cache[:asset_url].has_key?(index)
369
+ cached = node_cache[:asset_url][index]
370
+ if cached
371
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
372
+ @index = cached.interval.end
373
+ end
374
+ return cached
375
+ end
376
+
377
+ i0 = index
378
+ i1, s1 = index, []
379
+ if has_terminal?('"', false, index)
380
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
381
+ @index += 1
382
+ else
383
+ terminal_parse_failure('"')
384
+ r2 = nil
385
+ end
386
+ s1 << r2
387
+ if r2
388
+ s3, i3 = [], index
389
+ loop do
390
+ if has_terminal?('\G[^"]', true, index)
391
+ r4 = true
392
+ @index += 1
393
+ else
394
+ r4 = nil
395
+ end
396
+ if r4
397
+ s3 << r4
398
+ else
399
+ break
400
+ end
401
+ end
402
+ r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
403
+ s1 << r3
404
+ if r3
405
+ if has_terminal?('"', false, index)
406
+ r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
407
+ @index += 1
408
+ else
409
+ terminal_parse_failure('"')
410
+ r5 = nil
411
+ end
412
+ s1 << r5
413
+ end
414
+ end
415
+ if s1.last
416
+ r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
417
+ r1.extend(AssetUrl0)
418
+ else
419
+ @index = i1
420
+ r1 = nil
421
+ end
422
+ if r1
423
+ r0 = r1
424
+ else
425
+ i6, s6 = index, []
426
+ if has_terminal?("'", false, index)
427
+ r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
428
+ @index += 1
429
+ else
430
+ terminal_parse_failure("'")
431
+ r7 = nil
432
+ end
433
+ s6 << r7
434
+ if r7
435
+ s8, i8 = [], index
436
+ loop do
437
+ if has_terminal?('\G[^\']', true, index)
438
+ r9 = true
439
+ @index += 1
440
+ else
441
+ r9 = nil
442
+ end
443
+ if r9
444
+ s8 << r9
445
+ else
446
+ break
447
+ end
448
+ end
449
+ r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
450
+ s6 << r8
451
+ if r8
452
+ if has_terminal?("'", false, index)
453
+ r10 = instantiate_node(SyntaxNode,input, index...(index + 1))
454
+ @index += 1
455
+ else
456
+ terminal_parse_failure("'")
457
+ r10 = nil
458
+ end
459
+ s6 << r10
460
+ end
461
+ end
462
+ if s6.last
463
+ r6 = instantiate_node(SyntaxNode,input, i6...index, s6)
464
+ r6.extend(AssetUrl1)
465
+ else
466
+ @index = i6
467
+ r6 = nil
468
+ end
469
+ if r6
470
+ r0 = r6
471
+ else
472
+ s11, i11 = [], index
473
+ loop do
474
+ if has_terminal?('\G[\\S]', true, index)
475
+ r12 = true
476
+ @index += 1
477
+ else
478
+ r12 = nil
479
+ end
480
+ if r12
481
+ s11 << r12
482
+ else
483
+ break
484
+ end
485
+ end
486
+ if s11.empty?
487
+ @index = i11
488
+ r11 = nil
489
+ else
490
+ r11 = instantiate_node(SyntaxNode,input, i11...index, s11)
491
+ end
492
+ if r11
493
+ r0 = r11
494
+ else
495
+ @index = i0
496
+ r0 = nil
497
+ end
498
+ end
499
+ end
500
+
501
+ node_cache[:asset_url][start_index] = r0
502
+
503
+ r0
504
+ end
505
+
506
+ module Retrieve0
507
+ def statement_start
508
+ elements[0]
509
+ end
510
+
511
+ def var
512
+ elements[2]
513
+ end
514
+
515
+ def path
516
+ elements[4]
517
+ end
518
+ end
519
+
520
+ module Retrieve1
521
+ def to_package_statement(build_state)
522
+ return build_state.new_retrieve_statement(statement_start, var, path)
523
+ end
524
+ end
525
+
526
+ def _nt_retrieve
527
+ start_index = index
528
+ if node_cache[:retrieve].has_key?(index)
529
+ cached = node_cache[:retrieve][index]
530
+ if cached
531
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
532
+ @index = cached.interval.end
533
+ end
534
+ return cached
535
+ end
536
+
537
+ i0, s0 = index, []
538
+ if has_terminal?('retrieve', false, index)
539
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 8))
540
+ @index += 8
541
+ else
542
+ terminal_parse_failure('retrieve')
543
+ r1 = nil
544
+ end
545
+ s0 << r1
546
+ if r1
547
+ s2, i2 = [], index
548
+ loop do
549
+ r3 = _nt_ws_or_comment
550
+ if r3
551
+ s2 << r3
552
+ else
553
+ break
554
+ end
555
+ end
556
+ if s2.empty?
557
+ @index = i2
558
+ r2 = nil
559
+ else
560
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
561
+ end
562
+ s0 << r2
563
+ if r2
564
+ r4 = _nt_environment_variable_name
565
+ s0 << r4
566
+ if r4
567
+ if has_terminal?('->', false, index)
568
+ r5 = instantiate_node(SyntaxNode,input, index...(index + 2))
569
+ @index += 2
570
+ else
571
+ terminal_parse_failure('->')
572
+ r5 = nil
573
+ end
574
+ s0 << r5
575
+ if r5
576
+ r6 = _nt_retrieve_path
577
+ s0 << r6
578
+ end
579
+ end
580
+ end
581
+ end
582
+ if s0.last
583
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
584
+ r0.extend(Retrieve0)
585
+ r0.extend(Retrieve1)
586
+ else
587
+ @index = i0
588
+ r0 = nil
589
+ end
590
+
591
+ node_cache[:retrieve][start_index] = r0
592
+
593
+ r0
594
+ end
595
+
596
+ def _nt_retrieve_path
597
+ start_index = index
598
+ if node_cache[:retrieve_path].has_key?(index)
599
+ cached = node_cache[:retrieve_path][index]
600
+ if cached
601
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
602
+ @index = cached.interval.end
603
+ end
604
+ return cached
605
+ end
606
+
607
+ s0, i0 = [], index
608
+ loop do
609
+ if has_terminal?('\G[a-zA-Z0-9_/.\\[\\]-]', true, index)
610
+ r1 = true
611
+ @index += 1
612
+ else
613
+ r1 = nil
614
+ end
615
+ if r1
616
+ s0 << r1
617
+ else
618
+ break
619
+ end
620
+ end
621
+ if s0.empty?
622
+ @index = i0
623
+ r0 = nil
624
+ else
625
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
626
+ end
627
+
628
+ node_cache[:retrieve_path][start_index] = r0
629
+
630
+ r0
631
+ end
632
+
633
+ module Config0
634
+ def statement_start
635
+ elements[0]
636
+ end
637
+
638
+ def config_name
639
+ elements[2]
640
+ end
641
+
642
+ def statements
643
+ elements[4]
644
+ end
645
+
646
+ end
647
+
648
+ module Config1
649
+ def to_package_statement(build_state)
650
+ return build_state.new_configuration_statement(
651
+ statement_start, config_name, statements
652
+ )
653
+ end
654
+ end
655
+
656
+ def _nt_config
657
+ start_index = index
658
+ if node_cache[:config].has_key?(index)
659
+ cached = node_cache[:config][index]
660
+ if cached
661
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
662
+ @index = cached.interval.end
663
+ end
664
+ return cached
665
+ end
666
+
667
+ i0, s0 = index, []
668
+ if has_terminal?('config', false, index)
669
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 6))
670
+ @index += 6
671
+ else
672
+ terminal_parse_failure('config')
673
+ r1 = nil
674
+ end
675
+ s0 << r1
676
+ if r1
677
+ s2, i2 = [], index
678
+ loop do
679
+ r3 = _nt_ws_or_comment
680
+ if r3
681
+ s2 << r3
682
+ else
683
+ break
684
+ end
685
+ end
686
+ if s2.empty?
687
+ @index = i2
688
+ r2 = nil
689
+ else
690
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
691
+ end
692
+ s0 << r2
693
+ if r2
694
+ r4 = _nt_config_name
695
+ s0 << r4
696
+ if r4
697
+ s5, i5 = [], index
698
+ loop do
699
+ r6 = _nt_ws_or_comment
700
+ if r6
701
+ s5 << r6
702
+ else
703
+ break
704
+ end
705
+ end
706
+ if s5.empty?
707
+ @index = i5
708
+ r5 = nil
709
+ else
710
+ r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
711
+ end
712
+ s0 << r5
713
+ if r5
714
+ s7, i7 = [], index
715
+ loop do
716
+ r8 = _nt_config_statement_with_ws
717
+ if r8
718
+ s7 << r8
719
+ else
720
+ break
721
+ end
722
+ end
723
+ r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
724
+ s0 << r7
725
+ if r7
726
+ if has_terminal?('end', false, index)
727
+ r9 = instantiate_node(SyntaxNode,input, index...(index + 3))
728
+ @index += 3
729
+ else
730
+ terminal_parse_failure('end')
731
+ r9 = nil
732
+ end
733
+ s0 << r9
734
+ end
735
+ end
736
+ end
737
+ end
738
+ end
739
+ if s0.last
740
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
741
+ r0.extend(Config0)
742
+ r0.extend(Config1)
743
+ else
744
+ @index = i0
745
+ r0 = nil
746
+ end
747
+
748
+ node_cache[:config][start_index] = r0
749
+
750
+ r0
751
+ end
752
+
753
+ def _nt_config_name
754
+ start_index = index
755
+ if node_cache[:config_name].has_key?(index)
756
+ cached = node_cache[:config_name][index]
757
+ if cached
758
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
759
+ @index = cached.interval.end
760
+ end
761
+ return cached
762
+ end
763
+
764
+ s0, i0 = [], index
765
+ loop do
766
+ if has_terminal?('\G[a-zA-Z0-9_.-]', true, index)
767
+ r1 = true
768
+ @index += 1
769
+ else
770
+ r1 = nil
771
+ end
772
+ if r1
773
+ s0 << r1
774
+ else
775
+ break
776
+ end
777
+ end
778
+ if s0.empty?
779
+ @index = i0
780
+ r0 = nil
781
+ else
782
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
783
+ end
784
+
785
+ node_cache[:config_name][start_index] = r0
786
+
787
+ r0
788
+ end
789
+
790
+ module ConfigStatementWithWs0
791
+ def config_statement
792
+ elements[0]
793
+ end
794
+
795
+ end
796
+
797
+ module ConfigStatementWithWs1
798
+ def to_config_statement(build_state)
799
+ return config_statement.to_config_statement(build_state)
800
+ end
801
+ end
802
+
803
+ def _nt_config_statement_with_ws
804
+ start_index = index
805
+ if node_cache[:config_statement_with_ws].has_key?(index)
806
+ cached = node_cache[:config_statement_with_ws][index]
807
+ if cached
808
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
809
+ @index = cached.interval.end
810
+ end
811
+ return cached
812
+ end
813
+
814
+ i0, s0 = index, []
815
+ r1 = _nt_config_statement
816
+ s0 << r1
817
+ if r1
818
+ s2, i2 = [], index
819
+ loop do
820
+ r3 = _nt_ws_or_comment
821
+ if r3
822
+ s2 << r3
823
+ else
824
+ break
825
+ end
826
+ end
827
+ if s2.empty?
828
+ @index = i2
829
+ r2 = nil
830
+ else
831
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
832
+ end
833
+ s0 << r2
834
+ end
835
+ if s0.last
836
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
837
+ r0.extend(ConfigStatementWithWs0)
838
+ r0.extend(ConfigStatementWithWs1)
839
+ else
840
+ @index = i0
841
+ r0 = nil
842
+ end
843
+
844
+ node_cache[:config_statement_with_ws][start_index] = r0
845
+
846
+ r0
847
+ end
848
+
849
+ def _nt_config_statement
850
+ start_index = index
851
+ if node_cache[:config_statement].has_key?(index)
852
+ cached = node_cache[:config_statement][index]
853
+ if cached
854
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
855
+ @index = cached.interval.end
856
+ end
857
+ return cached
858
+ end
859
+
860
+ i0 = index
861
+ r1 = _nt_override
862
+ if r1
863
+ r0 = r1
864
+ else
865
+ r2 = _nt_include
866
+ if r2
867
+ r0 = r2
868
+ else
869
+ r3 = _nt_command
870
+ if r3
871
+ r0 = r3
872
+ else
873
+ r4 = _nt_path
874
+ if r4
875
+ r0 = r4
876
+ else
877
+ r5 = _nt_set
878
+ if r5
879
+ r0 = r5
880
+ else
881
+ @index = i0
882
+ r0 = nil
883
+ end
884
+ end
885
+ end
886
+ end
887
+ end
888
+
889
+ node_cache[:config_statement][start_index] = r0
890
+
891
+ r0
892
+ end
893
+
894
+ module Include0
895
+ def statement_start
896
+ elements[0]
897
+ end
898
+
899
+ def descriptor_string
900
+ elements[2]
901
+ end
902
+ end
903
+
904
+ module Include1
905
+ def to_config_statement(build_state)
906
+ return build_state.new_include_statement(
907
+ statement_start, descriptor_string
908
+ )
909
+ end
910
+ end
911
+
912
+ def _nt_include
913
+ start_index = index
914
+ if node_cache[:include].has_key?(index)
915
+ cached = node_cache[:include][index]
916
+ if cached
917
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
918
+ @index = cached.interval.end
919
+ end
920
+ return cached
921
+ end
922
+
923
+ i0, s0 = index, []
924
+ if has_terminal?('include', false, index)
925
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 7))
926
+ @index += 7
927
+ else
928
+ terminal_parse_failure('include')
929
+ r1 = nil
930
+ end
931
+ s0 << r1
932
+ if r1
933
+ s2, i2 = [], index
934
+ loop do
935
+ r3 = _nt_ws_or_comment
936
+ if r3
937
+ s2 << r3
938
+ else
939
+ break
940
+ end
941
+ end
942
+ if s2.empty?
943
+ @index = i2
944
+ r2 = nil
945
+ else
946
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
947
+ end
948
+ s0 << r2
949
+ if r2
950
+ r4 = _nt_descriptor_string
951
+ s0 << r4
952
+ end
953
+ end
954
+ if s0.last
955
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
956
+ r0.extend(Include0)
957
+ r0.extend(Include1)
958
+ else
959
+ @index = i0
960
+ r0 = nil
961
+ end
962
+
963
+ node_cache[:include][start_index] = r0
964
+
965
+ r0
966
+ end
967
+
968
+ module Override0
969
+ def statement_start
970
+ elements[0]
971
+ end
972
+
973
+ def descriptor_string
974
+ elements[2]
975
+ end
976
+ end
977
+
978
+ module Override1
979
+ def to_config_statement(build_state)
980
+ return build_state.new_override_statement(
981
+ statement_start, descriptor_string
982
+ )
983
+ end
984
+ end
985
+
986
+ def _nt_override
987
+ start_index = index
988
+ if node_cache[:override].has_key?(index)
989
+ cached = node_cache[:override][index]
990
+ if cached
991
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
992
+ @index = cached.interval.end
993
+ end
994
+ return cached
995
+ end
996
+
997
+ i0, s0 = index, []
998
+ if has_terminal?('override', false, index)
999
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 8))
1000
+ @index += 8
1001
+ else
1002
+ terminal_parse_failure('override')
1003
+ r1 = nil
1004
+ end
1005
+ s0 << r1
1006
+ if r1
1007
+ s2, i2 = [], index
1008
+ loop do
1009
+ r3 = _nt_ws_or_comment
1010
+ if r3
1011
+ s2 << r3
1012
+ else
1013
+ break
1014
+ end
1015
+ end
1016
+ if s2.empty?
1017
+ @index = i2
1018
+ r2 = nil
1019
+ else
1020
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
1021
+ end
1022
+ s0 << r2
1023
+ if r2
1024
+ r4 = _nt_descriptor_string
1025
+ s0 << r4
1026
+ end
1027
+ end
1028
+ if s0.last
1029
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1030
+ r0.extend(Override0)
1031
+ r0.extend(Override1)
1032
+ else
1033
+ @index = i0
1034
+ r0 = nil
1035
+ end
1036
+
1037
+ node_cache[:override][start_index] = r0
1038
+
1039
+ r0
1040
+ end
1041
+
1042
+ module Path0
1043
+ def statement_start
1044
+ elements[0]
1045
+ end
1046
+
1047
+ def name_value
1048
+ elements[2]
1049
+ end
1050
+ end
1051
+
1052
+ module Path1
1053
+ def to_config_statement(build_state)
1054
+ return build_state.new_environment_variable_statement(
1055
+ Statement::Path, statement_start, name_value
1056
+ )
1057
+ end
1058
+ end
1059
+
1060
+ def _nt_path
1061
+ start_index = index
1062
+ if node_cache[:path].has_key?(index)
1063
+ cached = node_cache[:path][index]
1064
+ if cached
1065
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1066
+ @index = cached.interval.end
1067
+ end
1068
+ return cached
1069
+ end
1070
+
1071
+ i0, s0 = index, []
1072
+ i1 = index
1073
+ if has_terminal?('add', false, index)
1074
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 3))
1075
+ @index += 3
1076
+ else
1077
+ terminal_parse_failure('add')
1078
+ r2 = nil
1079
+ end
1080
+ if r2
1081
+ r1 = r2
1082
+ else
1083
+ if has_terminal?('append', false, index)
1084
+ r3 = instantiate_node(SyntaxNode,input, index...(index + 6))
1085
+ @index += 6
1086
+ else
1087
+ terminal_parse_failure('append')
1088
+ r3 = nil
1089
+ end
1090
+ if r3
1091
+ r1 = r3
1092
+ else
1093
+ if has_terminal?('path', false, index)
1094
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 4))
1095
+ @index += 4
1096
+ else
1097
+ terminal_parse_failure('path')
1098
+ r4 = nil
1099
+ end
1100
+ if r4
1101
+ r1 = r4
1102
+ else
1103
+ @index = i1
1104
+ r1 = nil
1105
+ end
1106
+ end
1107
+ end
1108
+ s0 << r1
1109
+ if r1
1110
+ s5, i5 = [], index
1111
+ loop do
1112
+ r6 = _nt_ws_or_comment
1113
+ if r6
1114
+ s5 << r6
1115
+ else
1116
+ break
1117
+ end
1118
+ end
1119
+ if s5.empty?
1120
+ @index = i5
1121
+ r5 = nil
1122
+ else
1123
+ r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
1124
+ end
1125
+ s0 << r5
1126
+ if r5
1127
+ s7, i7 = [], index
1128
+ loop do
1129
+ if has_terminal?('\G[\\S]', true, index)
1130
+ r8 = true
1131
+ @index += 1
1132
+ else
1133
+ r8 = nil
1134
+ end
1135
+ if r8
1136
+ s7 << r8
1137
+ else
1138
+ break
1139
+ end
1140
+ end
1141
+ if s7.empty?
1142
+ @index = i7
1143
+ r7 = nil
1144
+ else
1145
+ r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
1146
+ end
1147
+ s0 << r7
1148
+ end
1149
+ end
1150
+ if s0.last
1151
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1152
+ r0.extend(Path0)
1153
+ r0.extend(Path1)
1154
+ else
1155
+ @index = i0
1156
+ r0 = nil
1157
+ end
1158
+
1159
+ node_cache[:path][start_index] = r0
1160
+
1161
+ r0
1162
+ end
1163
+
1164
+ def _nt_environment_variable_name
1165
+ start_index = index
1166
+ if node_cache[:environment_variable_name].has_key?(index)
1167
+ cached = node_cache[:environment_variable_name][index]
1168
+ if cached
1169
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1170
+ @index = cached.interval.end
1171
+ end
1172
+ return cached
1173
+ end
1174
+
1175
+ s0, i0 = [], index
1176
+ loop do
1177
+ if has_terminal?('\G[a-zA-Z0-9_]', true, index)
1178
+ r1 = true
1179
+ @index += 1
1180
+ else
1181
+ r1 = nil
1182
+ end
1183
+ if r1
1184
+ s0 << r1
1185
+ else
1186
+ break
1187
+ end
1188
+ end
1189
+ if s0.empty?
1190
+ @index = i0
1191
+ r0 = nil
1192
+ else
1193
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1194
+ end
1195
+
1196
+ node_cache[:environment_variable_name][start_index] = r0
1197
+
1198
+ r0
1199
+ end
1200
+
1201
+ module Set0
1202
+ def statement_start
1203
+ elements[0]
1204
+ end
1205
+
1206
+ def name_value
1207
+ elements[2]
1208
+ end
1209
+ end
1210
+
1211
+ module Set1
1212
+ def to_config_statement(build_state)
1213
+ return build_state.new_environment_variable_statement(
1214
+ Statement::Set, statement_start, name_value
1215
+ )
1216
+ end
1217
+ end
1218
+
1219
+ def _nt_set
1220
+ start_index = index
1221
+ if node_cache[:set].has_key?(index)
1222
+ cached = node_cache[:set][index]
1223
+ if cached
1224
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1225
+ @index = cached.interval.end
1226
+ end
1227
+ return cached
1228
+ end
1229
+
1230
+ i0, s0 = index, []
1231
+ if has_terminal?('set', false, index)
1232
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 3))
1233
+ @index += 3
1234
+ else
1235
+ terminal_parse_failure('set')
1236
+ r1 = nil
1237
+ end
1238
+ s0 << r1
1239
+ if r1
1240
+ s2, i2 = [], index
1241
+ loop do
1242
+ r3 = _nt_ws_or_comment
1243
+ if r3
1244
+ s2 << r3
1245
+ else
1246
+ break
1247
+ end
1248
+ end
1249
+ if s2.empty?
1250
+ @index = i2
1251
+ r2 = nil
1252
+ else
1253
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
1254
+ end
1255
+ s0 << r2
1256
+ if r2
1257
+ s4, i4 = [], index
1258
+ loop do
1259
+ if has_terminal?('\G[\\S]', true, index)
1260
+ r5 = true
1261
+ @index += 1
1262
+ else
1263
+ r5 = nil
1264
+ end
1265
+ if r5
1266
+ s4 << r5
1267
+ else
1268
+ break
1269
+ end
1270
+ end
1271
+ if s4.empty?
1272
+ @index = i4
1273
+ r4 = nil
1274
+ else
1275
+ r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
1276
+ end
1277
+ s0 << r4
1278
+ end
1279
+ end
1280
+ if s0.last
1281
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1282
+ r0.extend(Set0)
1283
+ r0.extend(Set1)
1284
+ else
1285
+ @index = i0
1286
+ r0 = nil
1287
+ end
1288
+
1289
+ node_cache[:set][start_index] = r0
1290
+
1291
+ r0
1292
+ end
1293
+
1294
+ module Command0
1295
+ def statement_start
1296
+ elements[0]
1297
+ end
1298
+
1299
+ def string
1300
+ elements[2]
1301
+ end
1302
+ end
1303
+
1304
+ module Command1
1305
+ def to_config_statement(build_state)
1306
+ return build_state.new_command_statement(statement_start, string)
1307
+ end
1308
+ end
1309
+
1310
+ def _nt_command
1311
+ start_index = index
1312
+ if node_cache[:command].has_key?(index)
1313
+ cached = node_cache[:command][index]
1314
+ if cached
1315
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1316
+ @index = cached.interval.end
1317
+ end
1318
+ return cached
1319
+ end
1320
+
1321
+ i0, s0 = index, []
1322
+ if has_terminal?('command', false, index)
1323
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 7))
1324
+ @index += 7
1325
+ else
1326
+ terminal_parse_failure('command')
1327
+ r1 = nil
1328
+ end
1329
+ s0 << r1
1330
+ if r1
1331
+ s2, i2 = [], index
1332
+ loop do
1333
+ r3 = _nt_ws_or_comment
1334
+ if r3
1335
+ s2 << r3
1336
+ else
1337
+ break
1338
+ end
1339
+ end
1340
+ if s2.empty?
1341
+ @index = i2
1342
+ r2 = nil
1343
+ else
1344
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
1345
+ end
1346
+ s0 << r2
1347
+ if r2
1348
+ r4 = _nt_string
1349
+ s0 << r4
1350
+ end
1351
+ end
1352
+ if s0.last
1353
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1354
+ r0.extend(Command0)
1355
+ r0.extend(Command1)
1356
+ else
1357
+ @index = i0
1358
+ r0 = nil
1359
+ end
1360
+
1361
+ node_cache[:command][start_index] = r0
1362
+
1363
+ r0
1364
+ end
1365
+
1366
+ module String0
1367
+ def value
1368
+ elements[1]
1369
+ end
1370
+
1371
+ end
1372
+
1373
+ def _nt_string
1374
+ start_index = index
1375
+ if node_cache[:string].has_key?(index)
1376
+ cached = node_cache[:string][index]
1377
+ if cached
1378
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1379
+ @index = cached.interval.end
1380
+ end
1381
+ return cached
1382
+ end
1383
+
1384
+ i0, s0 = index, []
1385
+ if has_terminal?('"', false, index)
1386
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
1387
+ @index += 1
1388
+ else
1389
+ terminal_parse_failure('"')
1390
+ r1 = nil
1391
+ end
1392
+ s0 << r1
1393
+ if r1
1394
+ s2, i2 = [], index
1395
+ loop do
1396
+ if has_terminal?('\G[^"]', true, index)
1397
+ r3 = true
1398
+ @index += 1
1399
+ else
1400
+ r3 = nil
1401
+ end
1402
+ if r3
1403
+ s2 << r3
1404
+ else
1405
+ break
1406
+ end
1407
+ end
1408
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
1409
+ s0 << r2
1410
+ if r2
1411
+ if has_terminal?('"', false, index)
1412
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
1413
+ @index += 1
1414
+ else
1415
+ terminal_parse_failure('"')
1416
+ r4 = nil
1417
+ end
1418
+ s0 << r4
1419
+ end
1420
+ end
1421
+ if s0.last
1422
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1423
+ r0.extend(String0)
1424
+ else
1425
+ @index = i0
1426
+ r0 = nil
1427
+ end
1428
+
1429
+ node_cache[:string][start_index] = r0
1430
+
1431
+ r0
1432
+ end
1433
+
1434
+ def _nt_descriptor_string
1435
+ start_index = index
1436
+ if node_cache[:descriptor_string].has_key?(index)
1437
+ cached = node_cache[:descriptor_string][index]
1438
+ if cached
1439
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1440
+ @index = cached.interval.end
1441
+ end
1442
+ return cached
1443
+ end
1444
+
1445
+ s0, i0 = [], index
1446
+ loop do
1447
+ if has_terminal?('\G[\\S]', true, index)
1448
+ r1 = true
1449
+ @index += 1
1450
+ else
1451
+ r1 = nil
1452
+ end
1453
+ if r1
1454
+ s0 << r1
1455
+ else
1456
+ break
1457
+ end
1458
+ end
1459
+ if s0.empty?
1460
+ @index = i0
1461
+ r0 = nil
1462
+ else
1463
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1464
+ end
1465
+
1466
+ node_cache[:descriptor_string][start_index] = r0
1467
+
1468
+ r0
1469
+ end
1470
+
1471
+ end
1472
+
1473
+ class V1Parser < Treetop::Runtime::CompiledParser
1474
+ include V1
1475
+ end
1476
+
1477
+ end
1478
+ end