liquid 4.0.3 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +89 -0
  3. data/README.md +10 -4
  4. data/lib/liquid/block.rb +31 -14
  5. data/lib/liquid/block_body.rb +169 -57
  6. data/lib/liquid/condition.rb +48 -21
  7. data/lib/liquid/context.rb +111 -52
  8. data/lib/liquid/document.rb +47 -9
  9. data/lib/liquid/drop.rb +4 -2
  10. data/lib/liquid/errors.rb +20 -18
  11. data/lib/liquid/expression.rb +28 -32
  12. data/lib/liquid/extensions.rb +2 -0
  13. data/lib/liquid/file_system.rb +6 -4
  14. data/lib/liquid/forloop_drop.rb +54 -4
  15. data/lib/liquid/i18n.rb +5 -3
  16. data/lib/liquid/interrupts.rb +3 -1
  17. data/lib/liquid/lexer.rb +30 -23
  18. data/lib/liquid/locales/en.yml +8 -5
  19. data/lib/liquid/parse_context.rb +20 -4
  20. data/lib/liquid/parse_tree_visitor.rb +2 -2
  21. data/lib/liquid/parser.rb +30 -18
  22. data/lib/liquid/parser_switching.rb +17 -3
  23. data/lib/liquid/partial_cache.rb +24 -0
  24. data/lib/liquid/profiler/hooks.rb +26 -14
  25. data/lib/liquid/profiler.rb +67 -86
  26. data/lib/liquid/range_lookup.rb +13 -3
  27. data/lib/liquid/registers.rb +51 -0
  28. data/lib/liquid/resource_limits.rb +47 -8
  29. data/lib/liquid/standardfilters.rb +551 -114
  30. data/lib/liquid/strainer_factory.rb +41 -0
  31. data/lib/liquid/strainer_template.rb +62 -0
  32. data/lib/liquid/tablerowloop_drop.rb +64 -5
  33. data/lib/liquid/tag/disableable.rb +22 -0
  34. data/lib/liquid/tag/disabler.rb +21 -0
  35. data/lib/liquid/tag.rb +28 -6
  36. data/lib/liquid/tags/assign.rb +36 -18
  37. data/lib/liquid/tags/break.rb +16 -3
  38. data/lib/liquid/tags/capture.rb +24 -18
  39. data/lib/liquid/tags/case.rb +61 -27
  40. data/lib/liquid/tags/comment.rb +18 -3
  41. data/lib/liquid/tags/continue.rb +16 -12
  42. data/lib/liquid/tags/cycle.rb +37 -25
  43. data/lib/liquid/tags/decrement.rb +22 -20
  44. data/lib/liquid/tags/echo.rb +41 -0
  45. data/lib/liquid/tags/for.rb +90 -87
  46. data/lib/liquid/tags/if.rb +50 -32
  47. data/lib/liquid/tags/ifchanged.rb +11 -10
  48. data/lib/liquid/tags/include.rb +49 -60
  49. data/lib/liquid/tags/increment.rb +23 -17
  50. data/lib/liquid/tags/inline_comment.rb +43 -0
  51. data/lib/liquid/tags/raw.rb +25 -11
  52. data/lib/liquid/tags/render.rb +109 -0
  53. data/lib/liquid/tags/table_row.rb +45 -19
  54. data/lib/liquid/tags/unless.rb +38 -19
  55. data/lib/liquid/template.rb +52 -72
  56. data/lib/liquid/template_factory.rb +9 -0
  57. data/lib/liquid/tokenizer.rb +18 -10
  58. data/lib/liquid/usage.rb +8 -0
  59. data/lib/liquid/utils.rb +13 -3
  60. data/lib/liquid/variable.rb +49 -44
  61. data/lib/liquid/variable_lookup.rb +18 -10
  62. data/lib/liquid/version.rb +2 -1
  63. data/lib/liquid.rb +18 -6
  64. metadata +20 -108
  65. data/lib/liquid/strainer.rb +0 -66
  66. data/lib/liquid/truffle.rb +0 -5
  67. data/test/fixtures/en_locale.yml +0 -9
  68. data/test/integration/assign_test.rb +0 -48
  69. data/test/integration/blank_test.rb +0 -106
  70. data/test/integration/block_test.rb +0 -12
  71. data/test/integration/capture_test.rb +0 -50
  72. data/test/integration/context_test.rb +0 -32
  73. data/test/integration/document_test.rb +0 -19
  74. data/test/integration/drop_test.rb +0 -273
  75. data/test/integration/error_handling_test.rb +0 -260
  76. data/test/integration/filter_test.rb +0 -178
  77. data/test/integration/hash_ordering_test.rb +0 -23
  78. data/test/integration/output_test.rb +0 -123
  79. data/test/integration/parse_tree_visitor_test.rb +0 -247
  80. data/test/integration/parsing_quirks_test.rb +0 -122
  81. data/test/integration/render_profiling_test.rb +0 -154
  82. data/test/integration/security_test.rb +0 -80
  83. data/test/integration/standard_filter_test.rb +0 -776
  84. data/test/integration/tags/break_tag_test.rb +0 -15
  85. data/test/integration/tags/continue_tag_test.rb +0 -15
  86. data/test/integration/tags/for_tag_test.rb +0 -410
  87. data/test/integration/tags/if_else_tag_test.rb +0 -188
  88. data/test/integration/tags/include_tag_test.rb +0 -253
  89. data/test/integration/tags/increment_tag_test.rb +0 -23
  90. data/test/integration/tags/raw_tag_test.rb +0 -31
  91. data/test/integration/tags/standard_tag_test.rb +0 -296
  92. data/test/integration/tags/statements_test.rb +0 -111
  93. data/test/integration/tags/table_row_test.rb +0 -64
  94. data/test/integration/tags/unless_else_tag_test.rb +0 -26
  95. data/test/integration/template_test.rb +0 -332
  96. data/test/integration/trim_mode_test.rb +0 -529
  97. data/test/integration/variable_test.rb +0 -96
  98. data/test/test_helper.rb +0 -116
  99. data/test/truffle/truffle_test.rb +0 -9
  100. data/test/unit/block_unit_test.rb +0 -58
  101. data/test/unit/condition_unit_test.rb +0 -166
  102. data/test/unit/context_unit_test.rb +0 -489
  103. data/test/unit/file_system_unit_test.rb +0 -35
  104. data/test/unit/i18n_unit_test.rb +0 -37
  105. data/test/unit/lexer_unit_test.rb +0 -51
  106. data/test/unit/parser_unit_test.rb +0 -82
  107. data/test/unit/regexp_unit_test.rb +0 -44
  108. data/test/unit/strainer_unit_test.rb +0 -164
  109. data/test/unit/tag_unit_test.rb +0 -21
  110. data/test/unit/tags/case_tag_unit_test.rb +0 -10
  111. data/test/unit/tags/for_tag_unit_test.rb +0 -13
  112. data/test/unit/tags/if_tag_unit_test.rb +0 -8
  113. data/test/unit/template_unit_test.rb +0 -78
  114. data/test/unit/tokenizer_unit_test.rb +0 -55
  115. data/test/unit/variable_unit_test.rb +0 -162
@@ -1,529 +0,0 @@
1
- require 'test_helper'
2
-
3
- class TrimModeTest < Minitest::Test
4
- include Liquid
5
-
6
- # Make sure the trim isn't applied to standard output
7
- def test_standard_output
8
- text = <<-END_TEMPLATE
9
- <div>
10
- <p>
11
- {{ 'John' }}
12
- </p>
13
- </div>
14
- END_TEMPLATE
15
- expected = <<-END_EXPECTED
16
- <div>
17
- <p>
18
- John
19
- </p>
20
- </div>
21
- END_EXPECTED
22
- assert_template_result(expected, text)
23
- end
24
-
25
- def test_variable_output_with_multiple_blank_lines
26
- text = <<-END_TEMPLATE
27
- <div>
28
- <p>
29
-
30
-
31
- {{- 'John' -}}
32
-
33
-
34
- </p>
35
- </div>
36
- END_TEMPLATE
37
- expected = <<-END_EXPECTED
38
- <div>
39
- <p>John</p>
40
- </div>
41
- END_EXPECTED
42
- assert_template_result(expected, text)
43
- end
44
-
45
- def test_tag_output_with_multiple_blank_lines
46
- text = <<-END_TEMPLATE
47
- <div>
48
- <p>
49
-
50
-
51
- {%- if true -%}
52
- yes
53
- {%- endif -%}
54
-
55
-
56
- </p>
57
- </div>
58
- END_TEMPLATE
59
- expected = <<-END_EXPECTED
60
- <div>
61
- <p>yes</p>
62
- </div>
63
- END_EXPECTED
64
- assert_template_result(expected, text)
65
- end
66
-
67
- # Make sure the trim isn't applied to standard tags
68
- def test_standard_tags
69
- whitespace = ' '
70
- text = <<-END_TEMPLATE
71
- <div>
72
- <p>
73
- {% if true %}
74
- yes
75
- {% endif %}
76
- </p>
77
- </div>
78
- END_TEMPLATE
79
- expected = <<-END_EXPECTED
80
- <div>
81
- <p>
82
- #{whitespace}
83
- yes
84
- #{whitespace}
85
- </p>
86
- </div>
87
- END_EXPECTED
88
- assert_template_result(expected, text)
89
-
90
- text = <<-END_TEMPLATE
91
- <div>
92
- <p>
93
- {% if false %}
94
- no
95
- {% endif %}
96
- </p>
97
- </div>
98
- END_TEMPLATE
99
- expected = <<-END_EXPECTED
100
- <div>
101
- <p>
102
- #{whitespace}
103
- </p>
104
- </div>
105
- END_EXPECTED
106
- assert_template_result(expected, text)
107
- end
108
-
109
- # Make sure the trim isn't too agressive
110
- def test_no_trim_output
111
- text = '<p>{{- \'John\' -}}</p>'
112
- expected = '<p>John</p>'
113
- assert_template_result(expected, text)
114
- end
115
-
116
- # Make sure the trim isn't too agressive
117
- def test_no_trim_tags
118
- text = '<p>{%- if true -%}yes{%- endif -%}</p>'
119
- expected = '<p>yes</p>'
120
- assert_template_result(expected, text)
121
-
122
- text = '<p>{%- if false -%}no{%- endif -%}</p>'
123
- expected = '<p></p>'
124
- assert_template_result(expected, text)
125
- end
126
-
127
- def test_single_line_outer_tag
128
- text = '<p> {%- if true %} yes {% endif -%} </p>'
129
- expected = '<p> yes </p>'
130
- assert_template_result(expected, text)
131
-
132
- text = '<p> {%- if false %} no {% endif -%} </p>'
133
- expected = '<p></p>'
134
- assert_template_result(expected, text)
135
- end
136
-
137
- def test_single_line_inner_tag
138
- text = '<p> {% if true -%} yes {%- endif %} </p>'
139
- expected = '<p> yes </p>'
140
- assert_template_result(expected, text)
141
-
142
- text = '<p> {% if false -%} no {%- endif %} </p>'
143
- expected = '<p> </p>'
144
- assert_template_result(expected, text)
145
- end
146
-
147
- def test_single_line_post_tag
148
- text = '<p> {% if true -%} yes {% endif -%} </p>'
149
- expected = '<p> yes </p>'
150
- assert_template_result(expected, text)
151
-
152
- text = '<p> {% if false -%} no {% endif -%} </p>'
153
- expected = '<p> </p>'
154
- assert_template_result(expected, text)
155
- end
156
-
157
- def test_single_line_pre_tag
158
- text = '<p> {%- if true %} yes {%- endif %} </p>'
159
- expected = '<p> yes </p>'
160
- assert_template_result(expected, text)
161
-
162
- text = '<p> {%- if false %} no {%- endif %} </p>'
163
- expected = '<p> </p>'
164
- assert_template_result(expected, text)
165
- end
166
-
167
- def test_pre_trim_output
168
- text = <<-END_TEMPLATE
169
- <div>
170
- <p>
171
- {{- 'John' }}
172
- </p>
173
- </div>
174
- END_TEMPLATE
175
- expected = <<-END_EXPECTED
176
- <div>
177
- <p>John
178
- </p>
179
- </div>
180
- END_EXPECTED
181
- assert_template_result(expected, text)
182
- end
183
-
184
- def test_pre_trim_tags
185
- text = <<-END_TEMPLATE
186
- <div>
187
- <p>
188
- {%- if true %}
189
- yes
190
- {%- endif %}
191
- </p>
192
- </div>
193
- END_TEMPLATE
194
- expected = <<-END_EXPECTED
195
- <div>
196
- <p>
197
- yes
198
- </p>
199
- </div>
200
- END_EXPECTED
201
- assert_template_result(expected, text)
202
-
203
- text = <<-END_TEMPLATE
204
- <div>
205
- <p>
206
- {%- if false %}
207
- no
208
- {%- endif %}
209
- </p>
210
- </div>
211
- END_TEMPLATE
212
- expected = <<-END_EXPECTED
213
- <div>
214
- <p>
215
- </p>
216
- </div>
217
- END_EXPECTED
218
- assert_template_result(expected, text)
219
- end
220
-
221
- def test_post_trim_output
222
- text = <<-END_TEMPLATE
223
- <div>
224
- <p>
225
- {{ 'John' -}}
226
- </p>
227
- </div>
228
- END_TEMPLATE
229
- expected = <<-END_EXPECTED
230
- <div>
231
- <p>
232
- John</p>
233
- </div>
234
- END_EXPECTED
235
- assert_template_result(expected, text)
236
- end
237
-
238
- def test_post_trim_tags
239
- text = <<-END_TEMPLATE
240
- <div>
241
- <p>
242
- {% if true -%}
243
- yes
244
- {% endif -%}
245
- </p>
246
- </div>
247
- END_TEMPLATE
248
- expected = <<-END_EXPECTED
249
- <div>
250
- <p>
251
- yes
252
- </p>
253
- </div>
254
- END_EXPECTED
255
- assert_template_result(expected, text)
256
-
257
- text = <<-END_TEMPLATE
258
- <div>
259
- <p>
260
- {% if false -%}
261
- no
262
- {% endif -%}
263
- </p>
264
- </div>
265
- END_TEMPLATE
266
- expected = <<-END_EXPECTED
267
- <div>
268
- <p>
269
- </p>
270
- </div>
271
- END_EXPECTED
272
- assert_template_result(expected, text)
273
- end
274
-
275
- def test_pre_and_post_trim_tags
276
- text = <<-END_TEMPLATE
277
- <div>
278
- <p>
279
- {%- if true %}
280
- yes
281
- {% endif -%}
282
- </p>
283
- </div>
284
- END_TEMPLATE
285
- expected = <<-END_EXPECTED
286
- <div>
287
- <p>
288
- yes
289
- </p>
290
- </div>
291
- END_EXPECTED
292
- assert_template_result(expected, text)
293
-
294
- text = <<-END_TEMPLATE
295
- <div>
296
- <p>
297
- {%- if false %}
298
- no
299
- {% endif -%}
300
- </p>
301
- </div>
302
- END_TEMPLATE
303
- expected = <<-END_EXPECTED
304
- <div>
305
- <p></p>
306
- </div>
307
- END_EXPECTED
308
- assert_template_result(expected, text)
309
- end
310
-
311
- def test_post_and_pre_trim_tags
312
- text = <<-END_TEMPLATE
313
- <div>
314
- <p>
315
- {% if true -%}
316
- yes
317
- {%- endif %}
318
- </p>
319
- </div>
320
- END_TEMPLATE
321
- expected = <<-END_EXPECTED
322
- <div>
323
- <p>
324
- yes
325
- </p>
326
- </div>
327
- END_EXPECTED
328
- assert_template_result(expected, text)
329
-
330
- whitespace = ' '
331
- text = <<-END_TEMPLATE
332
- <div>
333
- <p>
334
- {% if false -%}
335
- no
336
- {%- endif %}
337
- </p>
338
- </div>
339
- END_TEMPLATE
340
- expected = <<-END_EXPECTED
341
- <div>
342
- <p>
343
- #{whitespace}
344
- </p>
345
- </div>
346
- END_EXPECTED
347
- assert_template_result(expected, text)
348
- end
349
-
350
- def test_trim_output
351
- text = <<-END_TEMPLATE
352
- <div>
353
- <p>
354
- {{- 'John' -}}
355
- </p>
356
- </div>
357
- END_TEMPLATE
358
- expected = <<-END_EXPECTED
359
- <div>
360
- <p>John</p>
361
- </div>
362
- END_EXPECTED
363
- assert_template_result(expected, text)
364
- end
365
-
366
- def test_trim_tags
367
- text = <<-END_TEMPLATE
368
- <div>
369
- <p>
370
- {%- if true -%}
371
- yes
372
- {%- endif -%}
373
- </p>
374
- </div>
375
- END_TEMPLATE
376
- expected = <<-END_EXPECTED
377
- <div>
378
- <p>yes</p>
379
- </div>
380
- END_EXPECTED
381
- assert_template_result(expected, text)
382
-
383
- text = <<-END_TEMPLATE
384
- <div>
385
- <p>
386
- {%- if false -%}
387
- no
388
- {%- endif -%}
389
- </p>
390
- </div>
391
- END_TEMPLATE
392
- expected = <<-END_EXPECTED
393
- <div>
394
- <p></p>
395
- </div>
396
- END_EXPECTED
397
- assert_template_result(expected, text)
398
- end
399
-
400
- def test_whitespace_trim_output
401
- text = <<-END_TEMPLATE
402
- <div>
403
- <p>
404
- {{- 'John' -}},
405
- {{- '30' -}}
406
- </p>
407
- </div>
408
- END_TEMPLATE
409
- expected = <<-END_EXPECTED
410
- <div>
411
- <p>John,30</p>
412
- </div>
413
- END_EXPECTED
414
- assert_template_result(expected, text)
415
- end
416
-
417
- def test_whitespace_trim_tags
418
- text = <<-END_TEMPLATE
419
- <div>
420
- <p>
421
- {%- if true -%}
422
- yes
423
- {%- endif -%}
424
- </p>
425
- </div>
426
- END_TEMPLATE
427
- expected = <<-END_EXPECTED
428
- <div>
429
- <p>yes</p>
430
- </div>
431
- END_EXPECTED
432
- assert_template_result(expected, text)
433
-
434
- text = <<-END_TEMPLATE
435
- <div>
436
- <p>
437
- {%- if false -%}
438
- no
439
- {%- endif -%}
440
- </p>
441
- </div>
442
- END_TEMPLATE
443
- expected = <<-END_EXPECTED
444
- <div>
445
- <p></p>
446
- </div>
447
- END_EXPECTED
448
- assert_template_result(expected, text)
449
- end
450
-
451
- def test_complex_trim_output
452
- text = <<-END_TEMPLATE
453
- <div>
454
- <p>
455
- {{- 'John' -}}
456
- {{- '30' -}}
457
- </p>
458
- <b>
459
- {{ 'John' -}}
460
- {{- '30' }}
461
- </b>
462
- <i>
463
- {{- 'John' }}
464
- {{ '30' -}}
465
- </i>
466
- </div>
467
- END_TEMPLATE
468
- expected = <<-END_EXPECTED
469
- <div>
470
- <p>John30</p>
471
- <b>
472
- John30
473
- </b>
474
- <i>John
475
- 30</i>
476
- </div>
477
- END_EXPECTED
478
- assert_template_result(expected, text)
479
- end
480
-
481
- def test_complex_trim
482
- text = <<-END_TEMPLATE
483
- <div>
484
- {%- if true -%}
485
- {%- if true -%}
486
- <p>
487
- {{- 'John' -}}
488
- </p>
489
- {%- endif -%}
490
- {%- endif -%}
491
- </div>
492
- END_TEMPLATE
493
- expected = <<-END_EXPECTED
494
- <div><p>John</p></div>
495
- END_EXPECTED
496
- assert_template_result(expected, text)
497
- end
498
-
499
- def test_right_trim_followed_by_tag
500
- assert_template_result('ab c', '{{ "a" -}}{{ "b" }} c')
501
- end
502
-
503
- def test_raw_output
504
- whitespace = ' '
505
- text = <<-END_TEMPLATE
506
- <div>
507
- {% raw %}
508
- {%- if true -%}
509
- <p>
510
- {{- 'John' -}}
511
- </p>
512
- {%- endif -%}
513
- {% endraw %}
514
- </div>
515
- END_TEMPLATE
516
- expected = <<-END_EXPECTED
517
- <div>
518
- #{whitespace}
519
- {%- if true -%}
520
- <p>
521
- {{- 'John' -}}
522
- </p>
523
- {%- endif -%}
524
- #{whitespace}
525
- </div>
526
- END_EXPECTED
527
- assert_template_result(expected, text)
528
- end
529
- end # TrimModeTest
@@ -1,96 +0,0 @@
1
- require 'test_helper'
2
-
3
- class VariableTest < Minitest::Test
4
- include Liquid
5
-
6
- def test_simple_variable
7
- template = Template.parse(%({{test}}))
8
- assert_equal 'worked', template.render!('test' => 'worked')
9
- assert_equal 'worked wonderfully', template.render!('test' => 'worked wonderfully')
10
- end
11
-
12
- def test_variable_render_calls_to_liquid
13
- assert_template_result 'foobar', '{{ foo }}', 'foo' => ThingWithToLiquid.new
14
- end
15
-
16
- def test_simple_with_whitespaces
17
- template = Template.parse(%( {{ test }} ))
18
- assert_equal ' worked ', template.render!('test' => 'worked')
19
- assert_equal ' worked wonderfully ', template.render!('test' => 'worked wonderfully')
20
- end
21
-
22
- def test_ignore_unknown
23
- template = Template.parse(%({{ test }}))
24
- assert_equal '', template.render!
25
- end
26
-
27
- def test_using_blank_as_variable_name
28
- template = Template.parse("{% assign foo = blank %}{{ foo }}")
29
- assert_equal '', template.render!
30
- end
31
-
32
- def test_using_empty_as_variable_name
33
- template = Template.parse("{% assign foo = empty %}{{ foo }}")
34
- assert_equal '', template.render!
35
- end
36
-
37
- def test_hash_scoping
38
- template = Template.parse(%({{ test.test }}))
39
- assert_equal 'worked', template.render!('test' => { 'test' => 'worked' })
40
- end
41
-
42
- def test_false_renders_as_false
43
- assert_equal 'false', Template.parse("{{ foo }}").render!('foo' => false)
44
- assert_equal 'false', Template.parse("{{ false }}").render!
45
- end
46
-
47
- def test_nil_renders_as_empty_string
48
- assert_equal '', Template.parse("{{ nil }}").render!
49
- assert_equal 'cat', Template.parse("{{ nil | append: 'cat' }}").render!
50
- end
51
-
52
- def test_preset_assigns
53
- template = Template.parse(%({{ test }}))
54
- template.assigns['test'] = 'worked'
55
- assert_equal 'worked', template.render!
56
- end
57
-
58
- def test_reuse_parsed_template
59
- template = Template.parse(%({{ greeting }} {{ name }}))
60
- template.assigns['greeting'] = 'Goodbye'
61
- assert_equal 'Hello Tobi', template.render!('greeting' => 'Hello', 'name' => 'Tobi')
62
- assert_equal 'Hello ', template.render!('greeting' => 'Hello', 'unknown' => 'Tobi')
63
- assert_equal 'Hello Brian', template.render!('greeting' => 'Hello', 'name' => 'Brian')
64
- assert_equal 'Goodbye Brian', template.render!('name' => 'Brian')
65
- assert_equal({ 'greeting' => 'Goodbye' }, template.assigns)
66
- end
67
-
68
- def test_assigns_not_polluted_from_template
69
- template = Template.parse(%({{ test }}{% assign test = 'bar' %}{{ test }}))
70
- template.assigns['test'] = 'baz'
71
- assert_equal 'bazbar', template.render!
72
- assert_equal 'bazbar', template.render!
73
- assert_equal 'foobar', template.render!('test' => 'foo')
74
- assert_equal 'bazbar', template.render!
75
- end
76
-
77
- def test_hash_with_default_proc
78
- template = Template.parse(%(Hello {{ test }}))
79
- assigns = Hash.new { |h, k| raise "Unknown variable '#{k}'" }
80
- assigns['test'] = 'Tobi'
81
- assert_equal 'Hello Tobi', template.render!(assigns)
82
- assigns.delete('test')
83
- e = assert_raises(RuntimeError) do
84
- template.render!(assigns)
85
- end
86
- assert_equal "Unknown variable 'test'", e.message
87
- end
88
-
89
- def test_multiline_variable
90
- assert_equal 'worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked')
91
- end
92
-
93
- def test_render_symbol
94
- assert_template_result 'bar', '{{ foo }}', 'foo' => :bar
95
- end
96
- end