Skip to content

Commit dc7ed8f

Browse files
zzzyxwvutchrisbra
authored andcommitted
runtime(html): Optionally fold tags with the "expr" method
Tag folding poses a few difficulties. Many elements, e.g. "blockquote", are always delimited by start and end tags; end tags for some elements, e.g. "p", can be omitted in certain contexts; void elements, e.g. "hr", have no end tag. Although the rules for supporting omissible end tags are ad-hoc and involved, they apply to elements in scope. Assuming syntactical wellformedness, an end tag can be associated with its nearest matching start tag discoverable in scope and towards the beginning of a file, whereas all unbalanced tags and inlined tags can be disregarded. For example: ------------------------------------------------------------ <!DOCTYPE html> <html lang="en"> <!-- >1 : 1 --> <body> <!-- >2 : 2 --> <p>Paragraph #1. <!-- = : 2 --> <p> <!-- >3 : 3 --> Paragraph #2. <!-- = : 3 --> </p> <!-- <3 : 3 --> <p>Paragraph #3.</p> <!-- = : 2 --> </body> <!-- <2 : 2 --> </html> <!-- <1 : 1 --> ------------------------------------------------------------ (HTML comments here, "<!-- ... -->", record two values for each folded line that are separated by ":", a value obtained from "&foldexpr" and a value obtained from "foldlevel()".) Innermost foldedable tags will be flattened. For example: ------------------------------------------------------------ <!DOCTYPE html> <html lang="en"> <!-- >1 : 1 --> <body> <!-- >2 : 2 --> <div class="block"> <!-- >3 : 3 --> <pre><code> <!-- >4 : 4 --> [CODE SNIPPET] <!-- = : 4 --> </code></pre> <!-- <4 : 4 --> </div> <!-- <3 : 3 --> </body> <!-- <2 : 2 --> </html> <!-- <1 : 1 --> ------------------------------------------------------------ No folding will be requested for the "<code>"-"</code>" tag pair and reflected by "&foldexpr" because such a fold would have claimed the same lines that the immediate fold of the "<pre>"-"</pre>" tag already claims. Run-on folded tags may confuse Vim. When a file such as: ------------------------------------------------------------ <!DOCTYPE html> <html lang="en"> <!-- >1 : 1 --> <body> <!-- >2 : 2 --> <div class="block"> <!-- >3 : 3 --> <pre> <!-- >4 : 4 --> <code> <!-- >5 : 5 --> [CODE SNIPPET #1] <!-- = : 5 --> </code> <!-- <5 : 5 --> </pre> <!-- <4 : 4 --> </div> <!-- <3 : 3 --> <!-- = : 3 --> <div class="block"> <!-- >3 : 3 --> <pre> <!-- >4 : 4 --> <code> <!-- >5 : 5 --> [CODE SNIPPET #2] <!-- = : 5 --> </code> <!-- <5 : 5 --> </pre> <!-- <4 : 4 --> </div> <!-- <3 : 3 --> </body> <!-- <2 : 2 --> </html> <!-- <1 : 1 --> ------------------------------------------------------------ is reformatted as follows: ------------------------------------------------------------ <!DOCTYPE html> <html lang="en"> <!-- >1 : 1 --> <body> <!-- >2 : 2 --> <div class="block"> <!-- >3 : 3 --> <pre> <!-- >4 : 4 --> <code> <!-- >5 : 5 --> [CODE SNIPPET #1] <!-- = : 5 --> </code> <!-- <5 : 5 --> </pre> <!-- <4 : 4 --> </div><div class="block"><pre><code> <!-- <3 : 3 --> [CODE SNIPPET #2] <!-- = : 2 ? --> </code> <!-- <5 : 2 ? --> </pre> <!-- <4 : 2 ? --> </div> <!-- <3 : 2 ? --> </body> <!-- <2 : 2 --> </html> <!-- <1 : 1 --> ------------------------------------------------------------ "&foldexpr" values will not be used as is for the lines between (and including) "[CODE SNIPPET #2]" and "</div>". (Cf. v9.1.0002.) Having syntax highlighting in effect, tag folding using the "fold-expr" method can be enabled with: ------------------------------------------------------------ let g:html_expr_folding = 1 ------------------------------------------------------------ By default, tag folding will be redone from scratch after each occurrence of a TextChanged or an InsertLeave event. Such frequency may not be desired, especially for large files, and this recomputation can be disabled with: ------------------------------------------------------------ let g:html_expr_folding_without_recomputation = 1 doautocmd FileType ------------------------------------------------------------ To force another recomputation, do: ------------------------------------------------------------ unlet! b:foldsmap normal zx ------------------------------------------------------------ References: https://web.archive.org/web/20250328105626/https://html.spec.whatwg.org/multipage/syntax.html#optional-tags https://en.wikipedia.org/wiki/Dangling_else closes: vim#17141 Signed-off-by: Aliaksei Budavei <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent 3704b5b commit dc7ed8f

22 files changed

+764
-3
lines changed

runtime/autoload/htmlfold.vim

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
" HTML folding script, :h ft-html-plugin
2+
" Latest Change: 2025 May 10
3+
" Original Author: Aliaksei Budavei <[email protected]>
4+
5+
function! htmlfold#MapBalancedTags() abort
6+
" Describe only _a capturable-name prefix_ for start and end patterns of
7+
" a tag so that start tags with attributes spanning across lines can also be
8+
" matched with a single call of "getline()".
9+
let tag = '\m\c</\=\([0-9A-Za-z-]\+\)'
10+
let names = []
11+
let pairs = []
12+
let ends = []
13+
let pos = getpos('.')
14+
15+
try
16+
call cursor(1, 1)
17+
let [lnum, cnum] = searchpos(tag, 'cnW')
18+
19+
" Pair up nearest non-inlined tags in scope.
20+
while lnum > 0
21+
let name_attr = synIDattr(synID(lnum, cnum, 0), 'name')
22+
23+
if name_attr ==# 'htmlTag' || name_attr ==# 'htmlScriptTag'
24+
let name = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
25+
26+
if !empty(name)
27+
call insert(names, tolower(name), 0)
28+
call insert(pairs, [lnum, -1], 0)
29+
endif
30+
elseif name_attr ==# 'htmlEndTag'
31+
let name = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
32+
33+
if !empty(name)
34+
let idx = index(names, tolower(name))
35+
36+
if idx >= 0
37+
" Dismiss inlined balanced tags and opened-only tags.
38+
if pairs[idx][0] != lnum
39+
let pairs[idx][1] = lnum
40+
call add(ends, lnum)
41+
endif
42+
43+
" Claim a pair.
44+
let names[: idx] = repeat([''], (idx + 1))
45+
endif
46+
endif
47+
endif
48+
49+
" Advance the cursor, at "<", past "</a", "<a>", etc.
50+
call cursor(lnum, (cnum + 3))
51+
let [lnum, cnum] = searchpos(tag, 'cnW')
52+
endwhile
53+
finally
54+
call setpos('.', pos)
55+
endtry
56+
57+
if empty(ends)
58+
return {}
59+
endif
60+
61+
let folds = {}
62+
let pending_end = ends[0]
63+
let level = 0
64+
65+
while !empty(pairs)
66+
let [start, end] = remove(pairs, -1)
67+
68+
if end < 0
69+
continue
70+
endif
71+
72+
if start >= pending_end
73+
" Mark a sibling tag.
74+
call remove(ends, 0)
75+
76+
while start >= ends[0]
77+
" Mark a parent tag.
78+
call remove(ends, 0)
79+
let level -= 1
80+
endwhile
81+
82+
let pending_end = ends[0]
83+
else
84+
" Mark a child tag.
85+
let level += 1
86+
endif
87+
88+
" Flatten the innermost inlined folds.
89+
let folds[start] = get(folds, start, ('>' . level))
90+
let folds[end] = get(folds, end, ('<' . level))
91+
endwhile
92+
93+
return folds
94+
endfunction
95+
96+
" See ":help vim9-mix".
97+
if !has("vim9script")
98+
finish
99+
endif
100+
101+
def! g:htmlfold#MapBalancedTags(): dict<string>
102+
# Describe only _a capturable-name prefix_ for start and end patterns of
103+
# a tag so that start tags with attributes spanning across lines can also be
104+
# matched with a single call of "getline()".
105+
const tag: string = '\m\c</\=\([0-9A-Za-z-]\+\)'
106+
var names: list<string> = []
107+
var pairs: list<list<number>> = []
108+
var ends: list<number> = []
109+
const pos: list<number> = getpos('.')
110+
111+
try
112+
cursor(1, 1)
113+
var [lnum: number, cnum: number] = searchpos(tag, 'cnW')
114+
115+
# Pair up nearest non-inlined tags in scope.
116+
while lnum > 0
117+
const name_attr: string = synIDattr(synID(lnum, cnum, 0), 'name')
118+
119+
if name_attr ==# 'htmlTag' || name_attr ==# 'htmlScriptTag'
120+
const name: string = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
121+
122+
if !empty(name)
123+
insert(names, tolower(name), 0)
124+
insert(pairs, [lnum, -1], 0)
125+
endif
126+
elseif name_attr ==# 'htmlEndTag'
127+
const name: string = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
128+
129+
if !empty(name)
130+
const idx: number = index(names, tolower(name))
131+
132+
if idx >= 0
133+
# Dismiss inlined balanced tags and opened-only tags.
134+
if pairs[idx][0] != lnum
135+
pairs[idx][1] = lnum
136+
add(ends, lnum)
137+
endif
138+
139+
# Claim a pair.
140+
names[: idx] = repeat([''], (idx + 1))
141+
endif
142+
endif
143+
endif
144+
145+
# Advance the cursor, at "<", past "</a", "<a>", etc.
146+
cursor(lnum, (cnum + 3))
147+
[lnum, cnum] = searchpos(tag, 'cnW')
148+
endwhile
149+
finally
150+
setpos('.', pos)
151+
endtry
152+
153+
if empty(ends)
154+
return {}
155+
endif
156+
157+
var folds: dict<string> = {}
158+
var pending_end: number = ends[0]
159+
var level: number = 0
160+
161+
while !empty(pairs)
162+
const [start: number, end: number] = remove(pairs, -1)
163+
164+
if end < 0
165+
continue
166+
endif
167+
168+
if start >= pending_end
169+
# Mark a sibling tag.
170+
remove(ends, 0)
171+
172+
while start >= ends[0]
173+
# Mark a parent tag.
174+
remove(ends, 0)
175+
level -= 1
176+
endwhile
177+
178+
pending_end = ends[0]
179+
else
180+
# Mark a child tag.
181+
level += 1
182+
endif
183+
184+
# Flatten the innermost inlined folds.
185+
folds[start] = get(folds, start, ('>' .. level))
186+
folds[end] = get(folds, end, ('<' .. level))
187+
endwhile
188+
189+
return folds
190+
enddef
191+
192+
" vim: fdm=syntax sw=2 ts=8 noet

runtime/doc/filetype.txt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*filetype.txt* For Vim version 9.1. Last change: 2025 Apr 27
1+
*filetype.txt* For Vim version 9.1. Last change: 2025 May 10
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -702,6 +702,32 @@ HARE *ft-hare*
702702
Since the text for this plugin is rather long it has been put in a separate
703703
file: |ft_hare.txt|.
704704

705+
HTML *ft-html-plugin*
706+
707+
Tag folding poses a few difficulties. Many elements, e.g. `blockquote`, are
708+
always delimited by start and end tags; end tags for some elements, e.g. `p`,
709+
can be omitted in certain contexts; void elements, e.g. `hr`, have no end tag.
710+
Although the rules for supporting omissible end tags are ad-hoc and involved
711+
[0], they apply to elements in scope. Assuming syntactical wellformedness, an
712+
end tag can be associated with its nearest matching start tag discoverable in
713+
scope [1] and towards the beginning of a file, whereas all unbalanced tags and
714+
inlined tags can be disregarded. Having syntax highlighting in effect, tag
715+
folding using the |fold-expr| method can be enabled with: >
716+
let g:html_expr_folding = 1
717+
<
718+
By default, tag folding will be redone from scratch after each occurrence of
719+
a |TextChanged| or an |InsertLeave| event. Such frequency may not be desired,
720+
especially for large files, and this recomputation can be disabled with: >
721+
let g:html_expr_folding_without_recomputation = 1
722+
doautocmd FileType
723+
<
724+
To force another recomputation, do: >
725+
unlet! b:foldsmap
726+
normal zx
727+
<
728+
[0] https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
729+
[1] https://en.wikipedia.org/wiki/Dangling_else
730+
705731
IDRIS2 *ft-idris2-plugin*
706732

707733
By default the following options are set: >

runtime/doc/tags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7404,6 +7404,7 @@ ft-haskell-syntax syntax.txt /*ft-haskell-syntax*
74047404
ft-help-omni helphelp.txt /*ft-help-omni*
74057405
ft-html-indent indent.txt /*ft-html-indent*
74067406
ft-html-omni insert.txt /*ft-html-omni*
7407+
ft-html-plugin filetype.txt /*ft-html-plugin*
74077408
ft-html-syntax syntax.txt /*ft-html-syntax*
74087409
ft-htmlos-syntax syntax.txt /*ft-htmlos-syntax*
74097410
ft-ia64-syntax syntax.txt /*ft-ia64-syntax*

runtime/ftplugin/html.vim

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
" Maintainer: Doug Kearns <[email protected]>
44
" Previous Maintainer: Dan Sharp
55
" Last Change: 2024 Jan 14
6-
" 2024 May 24 by Riley Bruins <[email protected]> ('commentstring')
6+
" 2024 May 24 update 'commentstring' option
7+
" 2025 May 10 add expression folding #17141
78

89
if exists("b:did_ftplugin")
910
finish
@@ -56,5 +57,52 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
5657
let b:undo_ftplugin ..= " | unlet! b:browsefilter b:html_set_browsefilter"
5758
endif
5859

60+
if has("folding") && get(g:, "html_expr_folding", 0)
61+
function! HTMLTagFold() abort
62+
if empty(get(b:, "foldsmap", {}))
63+
if empty(get(b:, "current_syntax", ''))
64+
return '0'
65+
else
66+
let b:foldsmap = htmlfold#MapBalancedTags()
67+
endif
68+
endif
69+
70+
return get(b:foldsmap, v:lnum, '=')
71+
endfunction
72+
73+
setlocal foldexpr=HTMLTagFold()
74+
setlocal foldmethod=expr
75+
let b:undo_ftplugin ..= " | setlocal foldexpr< foldmethod<"
76+
77+
if !get(g:, "html_expr_folding_without_recomputation", 0)
78+
augroup htmltagfold
79+
autocmd! htmltagfold
80+
autocmd TextChanged,InsertLeave <buffer> let b:foldsmap = {}
81+
augroup END
82+
83+
" XXX: Keep ":autocmd" last in "b:undo_ftplugin" (see ":help :bar").
84+
let b:undo_ftplugin ..= " | silent! autocmd! htmltagfold * <buffer>"
85+
endif
86+
endif
87+
5988
let &cpo = s:save_cpo
6089
unlet s:save_cpo
90+
91+
" See ":help vim9-mix".
92+
if !has("vim9script")
93+
finish
94+
endif
95+
96+
if exists("*g:HTMLTagFold")
97+
def! g:HTMLTagFold(): string
98+
if empty(get(b:, "foldsmap", {}))
99+
if empty(get(b:, "current_syntax", ''))
100+
return '0'
101+
else
102+
b:foldsmap = g:htmlfold#MapBalancedTags()
103+
endif
104+
endif
105+
106+
return get(b:foldsmap, v:lnum, '=')
107+
enddef
108+
endif

runtime/syntax/html.vim

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
" Claudio Fleiner <[email protected]>
66
" Last Change: 2023 Nov 28
77
" 2024 Jul 30 by Vim Project: increase syn-sync-minlines to 250
8+
" 2025 May 10 by Vim Project: update comment
89

910
" See :help html.vim for some comments and a description of the options
1011

@@ -325,7 +326,8 @@ if main_syntax == "html"
325326
endif
326327

327328
" Folding
328-
" Originally by Ingo Karkat and Marcus Zanona
329+
" (Originally written by Ingo Karkat and Marcus Zanona; see
330+
" https://vi.stackexchange.com/questions/2306/html-syntax-folding-in-vim .)
329331
if get(g:, "html_syntax_folding", 0)
330332
syn region htmlFold start="<\z(\<\%(area\|base\|br\|col\|command\|embed\|hr\|img\|input\|keygen\|link\|meta\|param\|source\|track\|wbr\>\)\@![a-z-]\+\>\)\%(\_s*\_[^/]\?>\|\_s\_[^>]*\_[^>/]>\)" end="</\z1\_s*>" fold transparent keepend extend containedin=htmlHead,htmlH\d
331333
" fold comments (the real ones and the old Netscape ones)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
| +0#0000e05#a8a8a8255@7><+0&#ffffff0|!|D|O|C|T|Y|P|E| |h|t|m|l|>| +0#0000000&@51
2+
| +0#0000e05#a8a8a8255@7|<+0&#ffffff0|!|-@1| +0#0000000&@62
3+
| +0#0000e05#a8a8a8255@7|V+0&#ffffff0|I|M|_|T|E|S|T|_|S|E|T|U|P| |s|e|t|l|o|c|a|l| |f|o|l|d|c|o|l|u|m|n|=|8| |f|o|l|d|l|e|v|e|l|=|8| |f|o|l|d|m|e|t|h|o|d|=|e|x|p|r| +0#0000000&@2
4+
| +0#0000e05#a8a8a8255@7| +0#0000000#ffffff0@66
5+
| +0#0000e05#a8a8a8255@7| +0#0000000#ffffff0@66
6+
| +0#0000e05#a8a8a8255@7| +0#0000000#ffffff0@66
7+
| +0#0000e05#a8a8a8255@7|-+0&#ffffff0@1|>| +0#0000000&@63
8+
|-+0#0000e05#a8a8a8255| @6|<+0#00e0e07#ffffff0|h+0#af5f00255&|t|m|l| +0#00e0e07&|l+0#00e0003&|a|n|g|=+0#00e0e07&|"+0#e000002&|e|n|"|>+0#00e0e07&| +0#0000000&@7|<+0#0000e05&|!|-@1| |1| |-@1|>| +0#0000000&@32
9+
||+0#0000e05#a8a8a8255|-| @5|<+0#00e0e07#ffffff0|H+0#af5f00255&|E|A|D|>+0#00e0e07&| +0#e000e06&@17|<+0#0000e05&|!|-@1| |2| |-@1|>| +0#0000000&@32
10+
||+0#0000e05#a8a8a8255@1| @5|<+0#00e0e07#ffffff0|m+0#af5f00255&|e|t|a| +0#00e0e07&|c+0#00e0003&|h|a|r|s|e|t|=+0#00e0e07&|"+0#e000002&|U|T|F|-|8|"|>+0#00e0e07&| +0#0000000&@44
11+
||+0#0000e05#a8a8a8255@1| @5|<+0#00e0e07#ffffff0|t+0#af5f00255&|i|t|l|e|>+0#00e0e07&|A+0#e000e06&| |f|o|l|d|i|n|g| |s|y|n|t|a|x| |t|e|s|t|<+0#00e0e07&|/|t+0#af5f00255&|i|t|l|e|>+0#00e0e07&|<|s+0#af5f00255&|t|y|l|e|>+0#00e0e07&| +0#0000000&|/+0#0000e05&|*| |3| |F|I|X|M|E| |*|/| +0#0000000&@9
12+
||+0#0000e05#a8a8a8255@1| @5|p+0#af5f00255#ffffff0| +0#0000000&|{+0#00e0e07&| +0#0000000&|f+0#00e0003&|o|n|t|-|s|i|z|e|:+0#0000000&| |2+0#e000002&|4|p|x|;+0#0000000&| |}+0#00e0e07&| +0#0000000&|/+0#0000e05&|*| |<|/|s|t|y|l|e|>| +0#0000000&@32
13+
||+0#0000e05#a8a8a8255@1| @5|<+0#00e0e07#ffffff0|s+0#af5f00255&|t|y|l|e|>+0#00e0e07&|*+0#af5f00255&|/+0#0000000&|<+0#00e0e07&|/|s+0#af5f00255&|t|y|l|e|>+0#00e0e07&|<|/|h+0#af5f00255&|e|a|d|>+0#00e0e07&|<|/|h+0#af5f00255&|e|a|d|>+0#00e0e07&|<|/|h+0#af5f00255&|e|a|d|>+0#00e0e07&|<|/|h+0#af5f00255&|e|a|d|>+0#00e0e07&| +0#0000000&@21
14+
||+0#0000e05#a8a8a8255| @6| +0#0000000#ffffff0@66
15+
||+0#0000e05#a8a8a8255|-| @5|<+0#00e0e07#ffffff0|b+0#af5f00255&|O|d|Y| +0#00e0e07&|S+0#00e0003&|T|Y|L|E|=+0#00e0e07&|"+0#e000002&|b|a|c|k|g|r|o|u|n|d|:| |#|b|e|b|e|b|e|"|>+0#00e0e07&| +0#0000000&@5|<+0#0000e05&|!|-@1| |2| |-@1|>| +0#0000000&@16
16+
||+0#0000e05#a8a8a8255@1|-| @4|<+0#00e0e07#ffffff0|b+0#af5f00255&|r|>+0#00e0e07&|<|b+0#af5f00255&|r|>+0#00e0e07&|<|b+0#af5f00255&|r|>+0#00e0e07&|<|b+0#af5f00255&|r|>+0#00e0e07&|<|s+0#af5f00255&|c|r|i|p|t|>+0#00e0e07&|<+0#e000e06&|!|[+0#00e0e07&|C+0#e000e06&|D|A|T|A|[+0#00e0e07&| +0#e000e06&@6|/+0#0000e05&@1| |3| +0#0000000&@22
17+
||+0#0000e05#a8a8a8255@2| @4|/+0&#ffffff0@1| |\|x|3|C|!|-@1| +0#0000000&@56
18+
||+0#0000e05#a8a8a8255@2| @4|/+0&#ffffff0@1| |\|x|3|C|s|c|r|i|p|t|>| +0#0000000&@52
19+
||+0#0000e05#a8a8a8255@2| @4|/+0&#ffffff0@1| |\|x|3|C|/|s|c|r|i|p|t|>| +0#0000000&@51
20+
@57|1|,|1| @10|T|o|p|
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
||+0#0000e05#a8a8a8255| @6| +0#0000000#ffffff0@66
2+
||+0#0000e05#a8a8a8255|-| @5|<+0#00e0e07#ffffff0|b+0#af5f00255&|O|d|Y| +0#00e0e07&|S+0#00e0003&|T|Y|L|E|=+0#00e0e07&|"+0#e000002&|b|a|c|k|g|r|o|u|n|d|:| |#|b|e|b|e|b|e|"|>+0#00e0e07&| +0#0000000&@5|<+0#0000e05&|!|-@1| |2| |-@1|>| +0#0000000&@16
3+
||+0#0000e05#a8a8a8255@1|-| @4|<+0#00e0e07#ffffff0|b+0#af5f00255&|r|>+0#00e0e07&|<|b+0#af5f00255&|r|>+0#00e0e07&|<|b+0#af5f00255&|r|>+0#00e0e07&|<|b+0#af5f00255&|r|>+0#00e0e07&|<|s+0#af5f00255&|c|r|i|p|t|>+0#00e0e07&|<+0#e000e06&|!|[+0#00e0e07&|C+0#e000e06&|D|A|T|A|[+0#00e0e07&| +0#e000e06&@6|/+0#0000e05&@1| |3| +0#0000000&@22
4+
||+0#0000e05#a8a8a8255@2| @4|/+0&#ffffff0@1| |\|x|3|C|!|-@1| +0#0000000&@56
5+
||+0#0000e05#a8a8a8255@2| @4|/+0&#ffffff0@1| |\|x|3|C|s|c|r|i|p|t|>| +0#0000000&@52
6+
||+0#0000e05#a8a8a8255@2| @4>/+0&#ffffff0@1| |\|x|3|C|/|s|c|r|i|p|t|>| +0#0000000&@51
7+
||+0#0000e05#a8a8a8255@2| @4|/+0&#ffffff0@1| |-@1|>| +0#0000000&@60
8+
||+0#0000e05#a8a8a8255@2| @4|]+0#00e0e07#ffffff0@1|>+0#e000e06&|<+0#00e0e07&|/|s+0#af5f00255&|c|r|i|p|t|>+0#00e0e07&| +0#0000000&@54
9+
||+0#0000e05#a8a8a8255@1| @5|<+0#00e0e07#ffffff0|h+0#af5f00255&|2| +0#00e0e07&|i+0#00e0003&|d|=+0#00e0e07&|"+0#e000002&|>|<|/|h|2|>|"|>+0#00e0e07&|<|i+0#af5f00255&|>+0#00e0e07&|A+0#e000e06&|n| |H|2| |h|e|a|d|e|r|<+0#00e0e07&|/|i+0#af5f00255&|>+0#00e0e07&|<|/|h+0#af5f00255&|2|>+0#00e0e07&| +0#0000000&@26
10+
||+0#0000e05#a8a8a8255@1| @5|<+0#00e0e07#ffffff0|b+0#af5f00255&|r|>+0#00e0e07&|<|b+0#af5f00255&|r|>+0#00e0e07&|<|b+0#af5f00255&|r|>+0#00e0e07&|<|b+0#af5f00255&|r|>+0#00e0e07&| +0#0000000&@50
11+
||+0#0000e05#a8a8a8255@1| @5|<+0#00e0e07#ffffff0|h+0#af5f00255&|r|>+0#00e0e07&| +0#0000000&@62
12+
||+0#0000e05#a8a8a8255@1| @5| +0#0000000#ffffff0@66
13+
||+0#0000e05#a8a8a8255@1|-| @4|<+0#00e0e07#ffffff0|p+0#af5f00255&|>+0#00e0e07&|P+0#0000000&|a|r|a|g|r|a|p|h| |#|1|.| @7|<+0#0000e05&|!|-@1| |3| |-@1|>| +0#0000000&@32
14+
||+0#0000e05#a8a8a8255@2| @4|<+0#00e0e07#ffffff0|/|p+0#af5f00255&|>+0#00e0e07&| +0#0000000&@62
15+
||+0#0000e05#a8a8a8255@1| @5| +0#0000000#ffffff0@66
16+
||+0#0000e05#a8a8a8255@1| @5|<+0#00e0e07#ffffff0|p+0#af5f00255&|>+0#00e0e07&|P+0#0000000&|a|r|a|g|r|a|p|h| |#|2|.| @50
17+
||+0#0000e05#a8a8a8255@1| @5| +0#0000000#ffffff0@66
18+
||+0#0000e05#a8a8a8255@1|-| @4|<+0#00e0e07#ffffff0|d+0#af5f00255&|e|t|a|i|l|s|>+0#00e0e07&| +0#0000000&@14|<+0#0000e05&|!|-@1| |3| |<|/|d|e|t|a|i|l|s|>| |-@1|>| +0#0000000&@21
19+
||+0#0000e05#a8a8a8255@2|-| @3|<+0#00e0e07#ffffff0|s+0#af5f00255&|u|m@1|a|r|y|>+0#00e0e07&| +0#0000000&@14|<+0#0000e05&|!|-@1| |4| |<|/|s|u|m@1|a|r|y|>| |-@1|>| +0#0000000&@21
20+
@57|1|9|,|1| @9|1|5|%|
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
||+0#0000e05#a8a8a8255@2|-| @3|<+0#00e0e07#ffffff0|s+0#af5f00255&|u|m@1|a|r|y|>+0#00e0e07&| +0#0000000&@14|<+0#0000e05&|!|-@1| |4| |<|/|s|u|m@1|a|r|y|>| |-@1|>| +0#0000000&@21
2+
||+0#0000e05#a8a8a8255@3| @3|<+0#00e0e07#ffffff0|/|s+0#af5f00255&|u|m@1|a|r|y|>+0#00e0e07&| +0#0000000&@56
3+
||+0#0000e05#a8a8a8255@2| @4|<+0#00e0e07#ffffff0|p+0#af5f00255&|>+0#00e0e07&|P+0#0000000&|a|r|a|g|r|a|p|h| |#|1|.| @50
4+
||+0#0000e05#a8a8a8255@2|-| @3|<+0#00e0e07#ffffff0|u+0#af5f00255&|l|>+0#00e0e07&| +0#0000000&@19|<+0#0000e05&|!|-@1| |4| |-@1|>| +0#0000000&@32
5+
||+0#0000e05#a8a8a8255@3| @3|<+0#00e0e07#ffffff0|l+0#af5f00255&|i|>+0#00e0e07&|I+0#0000000&|t|e|m| |a|.|<+0#00e0e07&|/|l+0#af5f00255&|i|>+0#00e0e07&|<|l+0#af5f00255&|i|>+0#00e0e07&|I+0#0000000&|t|e|m| |b|.|<+0#00e0e07&|/|l+0#af5f00255&|i|>+0#00e0e07&| +0#0000000&@34
6+
||+0#0000e05#a8a8a8255@3| @3><+0#00e0e07#ffffff0|l+0#af5f00255&|i|>+0#00e0e07&|I+0#0000000&|t|e|m| |c|.| @55
7+
||+0#0000e05#a8a8a8255@3| @3|<+0#00e0e07#ffffff0|/|u+0#af5f00255&|l|>+0#00e0e07&| +0#0000000&@61
8+
||+0#0000e05#a8a8a8255@2|-| @3|<+0#00e0e07#ffffff0|p+0#af5f00255&|>+0#00e0e07&|P+0#0000000&|a|r|a|g|r|a|p|h| |#|2|.| @7|<+0#0000e05&|!|-@1| |4| |-@1|>| +0#0000000&@32
9+
||+0#0000e05#a8a8a8255@3| @3|<+0#00e0e07#ffffff0|/|p+0#af5f00255&|>+0#00e0e07&| +0#0000000&@62
10+
||+0#0000e05#a8a8a8255@2| @4|<+0#00e0e07#ffffff0|/|d+0#af5f00255&|e|t|a|i|l|s|>+0#00e0e07&| +0#0000000&@56
11+
||+0#0000e05#a8a8a8255@1| @5| +0#0000000#ffffff0@66
12+
||+0#0000e05#a8a8a8255@1|-| @4|<+0#00e0e07#ffffff0|d+0#af5f00255&|l|>+0#00e0e07&| +0#0000000&@19|<+0#0000e05&|!|-@1| |3| |-@1|>| +0#0000000&@32
13+
||+0#0000e05#a8a8a8255@2| @4|<+0#00e0e07#ffffff0|d+0#af5f00255&|t|>+0#00e0e07&|A+0#0000000&| |q|u|i|c|k| |b|r|o|w|n| |f|o|x| |j|u|m|p|s| |o|v|e|r| |t|h|e| |l|a|z|y| |d|o|g| @21
14+
||+0#0000e05#a8a8a8255@2| @4|<+0#00e0e07#ffffff0|d+0#af5f00255&@1|>+0#00e0e07&|W+0#0000000&|o@1|f|!| @57
15+
||+0#0000e05#a8a8a8255@2|-| @3|<+0#00e0e07#ffffff0|d+0#af5f00255&|l|>+0#00e0e07&| +0#0000000&@19|<+0#0000e05&|!|-@1| |4| |-@1|>| +0#0000000&@32
16+
||+0#0000e05#a8a8a8255@3| @3|<+0#00e0e07#ffffff0|d+0#af5f00255&|t|>+0#00e0e07&|A+0#0000000&| |q|u|i|c|k| |b|r|o|w|n| |f|o|x| |j|u|m|p|s| |o|v|e|r| |t|h|e| |l|a|z|y| |d|o|g| @21
17+
||+0#0000e05#a8a8a8255@3| @3|<+0#00e0e07#ffffff0|d+0#af5f00255&@1|>+0#00e0e07&|W+0#0000000&|o@1|f|!| @57
18+
||+0#0000e05#a8a8a8255@3| @3|<+0#00e0e07#ffffff0|/|d+0#af5f00255&|l|>+0#00e0e07&| +0#0000000&@61
19+
||+0#0000e05#a8a8a8255@2| @4|<+0#00e0e07#ffffff0|/|d+0#af5f00255&|l|>+0#00e0e07&| +0#0000000&@61
20+
@57|3|7|,|1| @9|3|6|%|

0 commit comments

Comments
 (0)