1 use super::render::text_renderer::{RichAnnotation, TaggedLine, TrivialDecorator};
2 use super::{from_read, from_read_with_decorator, parse, TextDecorator};
3 
4 /// Like assert_eq!(), but prints out the results normally as well
5 macro_rules! assert_eq_str {
6     ($a:expr, $b:expr) => {
7         if $a != $b {
8             println!("<<<\n{}===\n{}>>>", $a, $b);
9             assert_eq!($a, $b);
10         }
11     };
12 }
test_html(input: &[u8], expected: &str, width: usize)13 fn test_html(input: &[u8], expected: &str, width: usize) {
14     assert_eq_str!(from_read(input, width), expected);
15 }
16 
test_html_decorator<D>(input: &[u8], expected: &str, width: usize, decorator: D) where D: TextDecorator,17 fn test_html_decorator<D>(input: &[u8], expected: &str, width: usize, decorator: D)
18 where
19     D: TextDecorator,
20 {
21     let output = from_read_with_decorator(input, width, decorator);
22     assert_eq_str!(output, expected);
23 }
24 
25 #[test]
test_table()26 fn test_table() {
27     test_html(
28         br##"
29    <table>
30      <tr>
31        <td>1</td>
32        <td>2</td>
33        <td>3</td>
34      </tr>
35    </table>
36 "##,
37         r#"───┬───┬────
38 1  │2  │3
39 ───┴───┴────
40 "#,
41         12,
42     );
43 }
44 
45 #[test]
test_thead()46 fn test_thead() {
47     test_html(
48         br##"
49    <table>
50      <thead>
51        <tr>
52          <th>Col1</th>
53          <th>Col2</th>
54          <th>Col3</th>
55        </tr>
56      </thead>
57      <tbody>
58        <tr>
59          <td>1</td>
60          <td>2</td>
61          <td>3</td>
62        </tr>
63      </tbody>
64    </table>
65 "##,
66         r#"────┬────┬─────
67 Col1│Col2│Col3
68 ────┼────┼─────
69 1   │2   │3
70 ────┴────┴─────
71 "#,
72         15,
73     );
74 }
75 
76 #[test]
test_colspan()77 fn test_colspan() {
78     test_html(
79         br##"
80    <table>
81      <tr>
82        <td>1</td>
83        <td>2</td>
84        <td>3</td>
85      </tr>
86      <tr>
87        <td colspan="2">12</td>
88        <td>3</td>
89      </tr>
90      <tr>
91        <td>1</td>
92        <td colspan="2">23</td>
93      </tr>
94    </table>
95 "##,
96         r#"───┬───┬────
97 1  │2  │3
98 ───┴───┼────
99 12     │3
100 ───┬───┴────
101 1  │23
102 ───┴────────
103 "#,
104         12,
105     );
106 }
107 
108 #[test]
test_para()109 fn test_para() {
110     assert_eq_str!(from_read(&b"<p>Hello</p>"[..], 10), "Hello\n");
111 }
112 
113 #[test]
test_para2()114 fn test_para2() {
115     assert_eq_str!(
116         from_read(&b"<p>Hello, world!</p>"[..], 20),
117         "Hello, world!\n"
118     );
119 }
120 
121 #[test]
test_blockquote()122 fn test_blockquote() {
123     assert_eq_str!(
124         from_read(
125             &br#"<p>Hello</p>
126     <blockquote>One, two, three</blockquote>
127     <p>foo</p>
128 "#[..],
129             12
130         ),
131         r#"Hello
132 
133 > One, two,
134 > three
135 
136 foo
137 "#
138     );
139 }
140 
141 #[test]
test_ul()142 fn test_ul() {
143     test_html(
144         br#"
145         <ul>
146           <li>Item one</li>
147           <li>Item two</li>
148           <li>Item three</li>
149         </ul>
150      "#,
151         r#"* Item one
152 * Item two
153 * Item
154   three
155 "#,
156         10,
157     );
158 }
159 
160 #[test]
test_ol1()161 fn test_ol1() {
162     test_html(
163         br#"
164         <ol>
165           <li>Item one</li>
166           <li>Item two</li>
167           <li>Item three</li>
168         </ol>
169      "#,
170         r#"1. Item one
171 2. Item two
172 3. Item
173    three
174 "#,
175         11,
176     );
177 }
178 
179 #[test]
test_ol2()180 fn test_ol2() {
181     test_html(
182         br#"
183         <ol>
184           <li>Item one</li>
185           <li>Item two</li>
186           <li>Item three</li>
187           <li>Item four</li>
188           <li>Item five</li>
189           <li>Item six</li>
190           <li>Item seven</li>
191           <li>Item eight</li>
192           <li>Item nine</li>
193           <li>Item ten</li>
194         </ol>
195      "#,
196         r#"1.  Item one
197 2.  Item two
198 3.  Item three
199 4.  Item four
200 5.  Item five
201 6.  Item six
202 7.  Item seven
203 8.  Item eight
204 9.  Item nine
205 10. Item ten
206 "#,
207         20,
208     );
209 }
210 
211 #[test]
test_ol_start()212 fn test_ol_start() {
213     test_html(
214         br#"
215         <ol start="3">
216           <li>Item three</li>
217           <li>Item four</li>
218         </ol>
219      "#,
220         r#"3. Item three
221 4. Item four
222 "#,
223         20,
224     );
225 }
226 
227 #[test]
test_ol_start_9()228 fn test_ol_start_9() {
229     test_html(
230         br#"
231         <ol start="9">
232           <li>Item nine</li>
233           <li>Item ten</li>
234         </ol>
235      "#,
236         r#"9.  Item nine
237 10. Item ten
238 "#,
239         20,
240     );
241 }
242 
243 #[test]
test_ol_start_neg()244 fn test_ol_start_neg() {
245     test_html(
246         br#"
247         <ol start="-1">
248           <li>Item minus one</li>
249           <li>Item zero</li>
250           <li>Item one</li>
251         </ol>
252      "#,
253         r#"-1. Item minus one
254 0.  Item zero
255 1.  Item one
256 "#,
257         20,
258     );
259 }
260 
261 #[test]
test_strip_nl()262 fn test_strip_nl() {
263     test_html(
264         br#"
265         <p>
266            One
267            Two
268            Three
269         </p>
270      "#,
271         "One Two Three\n",
272         40,
273     );
274 }
275 #[test]
test_strip_nl2()276 fn test_strip_nl2() {
277     test_html(
278         br#"
279         <p>
280            One
281            <span>
282                Two
283            </span>
284            Three
285         </p>
286      "#,
287         "One Two Three\n",
288         40,
289     );
290 }
291 #[test]
test_strip_nl_tbl()292 fn test_strip_nl_tbl() {
293     test_html(
294         br#"
295        <table>
296          <tr>
297             <td>
298                One
299                <span>
300                    Two
301                </span>
302                Three
303             </td>
304           </tr>
305         </table>
306      "#,
307         r"────────────────────
308 One Two Three
309 ────────────────────
310 ",
311         20,
312     );
313 }
314 #[test]
test_unknown_element()315 fn test_unknown_element() {
316     test_html(
317         br#"
318        <foo>
319        <table>
320          <tr>
321             <td>
322                One
323                <span><yyy>
324                    Two
325                </yyy></span>
326                Three
327             </td>
328           </tr>
329         </table>
330         </foo>
331      "#,
332         r"────────────────────
333 One Two Three
334 ────────────────────
335 ",
336         20,
337     );
338 }
339 #[test]
test_strip_nl_tbl_p()340 fn test_strip_nl_tbl_p() {
341     test_html(
342         br#"
343        <table>
344          <tr>
345             <td><p>
346                One
347                <span>
348                    Two
349                </span>
350                Three
351             </p></td>
352           </tr>
353         </table>
354      "#,
355         r"────────────────────
356 One Two Three
357 ────────────────────
358 ",
359         20,
360     );
361 }
362 #[test]
test_pre()363 fn test_pre() {
364     test_html(
365         br#"
366        <pre>foo
367 bar
368 wib   asdf;
369 </pre>
370 <p>Hello</p>
371      "#,
372         r"foo
373 bar
374 wib   asdf;
375 
376 Hello
377 ",
378         20,
379     );
380 }
381 #[test]
test_link()382 fn test_link() {
383     test_html(
384         br#"
385        <p>Hello, <a href="http://www.example.com/">world</a></p>"#,
386         r"Hello, [world][1]
387 
388 [1] http://www.example.com/
389 ",
390         80,
391     );
392 }
393 #[test]
test_link2()394 fn test_link2() {
395     test_html(
396         br#"
397        <p>Hello, <a href="http://www.example.com/">world</a>!</p>"#,
398         r"Hello, [world][1]!
399 
400 [1] http://www.example.com/
401 ",
402         80,
403     );
404 }
405 
406 #[test]
test_link3()407 fn test_link3() {
408     test_html(
409         br#"
410        <p>Hello, <a href="http://www.example.com/">w</a>orld</p>"#,
411         r"Hello, [w][1]orld
412 
413 [1] http://www.example.com/
414 ",
415         80,
416     );
417 }
418 
419 #[test]
test_link_wrap()420 fn test_link_wrap() {
421     test_html(
422         br#"
423        <a href="http://www.example.com/">Hello</a>"#,
424         r"[Hello][1]
425 
426 [1] http:/
427 /www.examp
428 le.com/
429 ",
430         10,
431     );
432 }
433 
434 #[test]
test_wrap()435 fn test_wrap() {
436     test_html(
437         br"<p>Hello, world.  Superlongwordreally</p>",
438         r#"Hello,
439 world.
440 Superlon
441 gwordrea
442 lly
443 "#,
444         8,
445     );
446 }
447 
448 #[test]
test_wrap2()449 fn test_wrap2() {
450     test_html(
451         br"<p>Hello, world.  This is a long sentence with a
452 few words, which we want to be wrapped correctly.</p>",
453         r#"Hello, world. This
454 is a long sentence
455 with a few words,
456 which we want to be
457 wrapped correctly.
458 "#,
459         20,
460     );
461 }
462 
463 #[test]
test_wrap3()464 fn test_wrap3() {
465     test_html(
466         br#"<p><a href="dest">http://example.org/blah/</a> one two three"#,
467         r#"[http://example.org/blah/
468 ][1] one two three
469 
470 [1] dest
471 "#,
472         25,
473     );
474 }
475 
476 #[test]
test_div()477 fn test_div() {
478     test_html(
479         br"<p>Hello</p><div>Div</div>",
480         r#"Hello
481 
482 Div
483 "#,
484         20,
485     );
486     test_html(
487         br"<p>Hello</p><div>Div</div><div>Div2</div>",
488         r#"Hello
489 
490 Div
491 Div2
492 "#,
493         20,
494     );
495 }
496 
497 #[test]
test_img_alt()498 fn test_img_alt() {
499     test_html(
500         br"<p>Hello <img src='foo.jpg' alt='world'></p>",
501         "Hello [world]\n",
502         80,
503     );
504 }
505 
506 #[test]
test_br()507 fn test_br() {
508     test_html(br"<p>Hello<br/>World</p>", "Hello\nWorld\n", 20);
509 }
510 
511 #[test]
test_br2()512 fn test_br2() {
513     test_html(br"<p>Hello<br/><br/>World</p>", "Hello\n\nWorld\n", 20);
514 }
515 
516 #[test]
test_br3()517 fn test_br3() {
518     test_html(br"<p>Hello<br/> <br/>World</p>", "Hello\n\nWorld\n", 20);
519 }
520 
521 #[test]
test_subblock()522 fn test_subblock() {
523     test_html(
524         br#"<div>
525      <div>Here's a <a href="https://example.com/">link</a>.</div>
526      <div><ul>
527      <li>Bullet</li>
528      <li>Bullet</li>
529      <li>Bullet</li>
530      </ul></div>
531      </div>"#,
532         r"Here's a [link][1].
533 
534 * Bullet
535 * Bullet
536 * Bullet
537 
538 [1] https://example.com/
539 ",
540         80,
541     );
542 }
543 
544 #[test]
545 fn test_controlchar() {
546     test_html("Foo\u{0080}Bar".as_bytes(), "FooBar\n", 80);
547     test_html("Foo\u{0080}Bar".as_bytes(), "FooB\nar\n", 4);
548     test_html("FooBa\u{0080}r".as_bytes(), "FooB\nar\n", 4);
549 }
550 
551 #[test]
552 fn test_nested_table_1() {
553     test_html(
554         br##"
555    <table>
556      <tr>
557        <td>
558           <table><tr><td>1</td><td>2</td><td>3</td></tr></table>
559        </td>
560        <td>
561           <table><tr><td>4</td><td>5</td><td>6</td></tr></table>
562        </td>
563        <td>
564           <table><tr><td>7</td><td>8</td><td>9</td></tr></table>
565        </td>
566      </tr>
567      <tr>
568        <td>
569           <table><tr><td>1</td><td>2</td><td>3</td></tr></table>
570        </td>
571        <td>
572           <table><tr><td>4</td><td>5</td><td>6</td></tr></table>
573        </td>
574        <td>
575           <table><tr><td>7</td><td>8</td><td>9</td></tr></table>
576        </td>
577      </tr>
578      <tr>
579        <td>
580           <table><tr><td>1</td><td>2</td><td>3</td></tr></table>
581        </td>
582        <td>
583           <table><tr><td>4</td><td>5</td><td>6</td></tr></table>
584        </td>
585        <td>
586           <table><tr><td>7</td><td>8</td><td>9</td></tr></table>
587        </td>
588      </tr>
589    </table>
590 "##,
591         r#"─┬─┬──┬─┬─┬──┬─┬─┬───
592 1│2│3 │4│5│6 │7│8│9
593 ─┼─┼──┼─┼─┼──┼─┼─┼───
594 1│2│3 │4│5│6 │7│8│9
595 ─┼─┼──┼─┼─┼──┼─┼─┼───
596 1│2│3 │4│5│6 │7│8│9
597 ─┴─┴──┴─┴─┴──┴─┴─┴───
598 "#,
599         21,
600     );
601 }
602 
603 #[test]
604 fn test_nested_table_2() {
605     test_html(
606         br##"
607    <table>
608      <tr>
609        <td>
610           <table>
611              <tr><td>1</td><td>a</td></tr>
612              <tr><td>2</td><td>b</td></tr>
613           </table>
614        </td>
615        <td><pre>one
616 two
617 three
618 four
619 five
620 </pre>
621        </td>
622      </tr>
623    </table>
624 "##,
625         r#"─┬───┬─────
626 1│a  │one
627 ─┼───│two
628 2│b  │three
629  │   │four
630  │   │five
631 ─┴───┴─────
632 "#,
633         11,
634     );
635 }
636 
637 #[test]
638 fn test_h1() {
639     test_html(
640         br##"
641    <h1>Hi</h1>
642    <p>foo</p>
643 "##,
644         r#"# Hi
645 
646 foo
647 "#,
648         21,
649     );
650 }
651 
652 #[test]
653 fn test_h3() {
654     test_html(
655         br##"
656    <h3>Hi</h3>
657    <p>foo</p>
658 "##,
659         r#"### Hi
660 
661 foo
662 "#,
663         21,
664     );
665 }
666 
667 // General test that spacing is preserved
668 #[test]
669 fn test_pre2() {
670     test_html(
671         br##"<pre>Hello  sp
672 world</pre>"##,
673         r#"Hello  sp
674 world
675 "#,
676         21,
677     );
678 }
679 
680 // Check that spans work correctly inside <pre>
681 #[test]
682 fn test_pre_span() {
683     test_html(
684         br##"
685 <pre>Hello <span>$</span>sp
686 <span>Hi</span> <span>$</span><span>foo</span>
687 <span>Hi</span> <span>foo</span><span>, </span><span>bar</span>
688 </pre>"##,
689         r#"Hello $sp
690 Hi $foo
691 Hi foo, bar
692 "#,
693         21,
694     );
695 }
696 
697 // Check tab behaviour
698 #[test]
699 fn test_pre_tab() {
700     test_html(b"<pre>\tworld</pre>", "        world\n", 40);
701     test_html(b"<pre>H\tworld</pre>", "H       world\n", 40);
702     test_html(b"<pre>He\tworld</pre>", "He      world\n", 40);
703     test_html(b"<pre>Hel\tworld</pre>", "Hel     world\n", 40);
704     test_html(b"<pre>Hell\tworld</pre>", "Hell    world\n", 40);
705     test_html(b"<pre>Hello\tworld</pre>", "Hello   world\n", 40);
706     test_html(b"<pre>Helloo\tworld</pre>", "Helloo  world\n", 40);
707     test_html(b"<pre>Hellooo\tworld</pre>", "Hellooo world\n", 40);
708     test_html(b"<pre>Helloooo\tworld</pre>", "Helloooo        world\n", 40);
709 }
710 
711 #[test]
712 fn test_em_strong() {
713     test_html(
714         br##"
715    <p>Hi <em>em</em> <strong>strong</strong></p>
716 "##,
717         r#"Hi *em* **strong**
718 "#,
719         21,
720     );
721 }
722 
723 #[test]
724 #[ignore] // Not yet fixed!
725 fn test_nbsp_indent() {
726     test_html(
727         br##"
728    <div>Top</div>
729    <div>&nbsp;Indented</div>
730    <div>&nbsp;&nbsp;Indented again</div>
731 "##,
732         r#"Top
733 Indented
734 Indented again
735 "#,
736         21,
737     );
738 }
739 
740 #[test]
741 fn test_deeply_nested() {
742     use ::std::iter::repeat;
743     let html = repeat("<foo>").take(1000).collect::<Vec<_>>().concat();
744     test_html(html.as_bytes(), "", 10);
745 }
746 
747 #[test]
748 fn test_deeply_nested_table() {
749     use ::std::iter::repeat;
750     let html = repeat("<table><tr><td>hi</td><td>")
751         .take(1000)
752         .collect::<Vec<_>>()
753         .concat()
754         + &repeat("</td></tr></table>")
755             .take(1000)
756             .collect::<Vec<_>>()
757             .concat();
758     test_html(
759         html.as_bytes(),
760         r#"────┬─┬───
761 hi  │h│
762     │i│
763 ────┴─┴───
764 "#,
765         10,
766     );
767 }
768 
769 #[test]
770 fn test_table_no_id() {
771     let html = r#"<html><body><table>
772         <tr>
773             <td>hi, world</td>
774         </tr>
775     </table></body></html>"#;
776     test_html(
777         html.as_bytes(),
778         r#"──────────
779 hi, world
780 ──────────
781 "#,
782         10,
783     );
784 }
785 
786 #[test]
787 fn test_table_cell_id() {
788     let html = r#"<html><body><table>
789         <tr>
790             <td id="bodyCell">hi, world</td>
791         </tr>
792     </table></body></html>"#;
793     test_html(
794         html.as_bytes(),
795         r#"──────────
796 hi, world
797 ──────────
798 "#,
799         10,
800     );
801 }
802 
803 #[test]
804 fn test_table_row_id() {
805     let html = r#"<html><body><table>
806         <tr id="bodyrow">
807             <td>hi, world</td>
808         </tr>
809     </table></body></html>"#;
810     test_html(
811         html.as_bytes(),
812         r#"──────────
813 hi, world
814 ──────────
815 "#,
816         10,
817     );
818 }
819 
820 #[test]
821 fn test_table_table_id() {
822     let html = r#"<html><body><table id="bodytable">
823         <tr>
824             <td>hi, world</td>
825         </tr>
826     </table></body></html>"#;
827     test_html(
828         html.as_bytes(),
829         r#"──────────
830 hi, world
831 ──────────
832 "#,
833         10,
834     );
835 }
836 
837 #[test]
838 fn test_table_tbody_id() {
839     let html = r#"<html><body><table>
840       <tbody id="tb">
841         <tr>
842             <td>hi, world</td>
843         </tr>
844       </tbody>
845     </table></body></html>"#;
846     test_html(
847         html.as_bytes(),
848         r#"──────────
849 hi, world
850 ──────────
851 "#,
852         10,
853     );
854 }
855 
856 #[test]
857 fn test_header_width() {
858     //0 size
859     test_html(
860         br##"
861         <h2>
862             <table>
863                         <h3>Anything</h3>
864             </table>
865         </h2>
866 "##,
867         r#"## ### A
868 ## ### n
869 ## ### y
870 ## ### t
871 ## ### h
872 ## ### i
873 ## ### n
874 ## ### g
875 ##
876 ## ────
877 "#,
878         7,
879     );
880     //Underflow
881     test_html(
882         br##"
883         <h2>
884             <table>
885                 <h3>Anything</h3>
886             </table>
887         </h2>
888 "##,
889         r#"## ### A
890 ## ### n
891 ## ### y
892 ## ### t
893 ## ### h
894 ## ### i
895 ## ### n
896 ## ### g
897 ##
898 ## ──
899 "#,
900         5,
901     );
902 }
903 
904 #[test]
905 fn test_trivial_decorator() {
906     test_html_decorator(
907         br#"<div>
908      <div>Here's a <a href="https://example.com/">link</a>.</div>
909      <div><ul>
910      <li>Bullet</li>
911      <li>Bullet</li>
912      <li>Bullet</li>
913      </ul></div>
914      </div>"#,
915         r"Here's a link.
916 
917 * Bullet
918 * Bullet
919 * Bullet
920 ",
921         80,
922         TrivialDecorator::new(),
923     );
924 }
925 
926 #[test]
927 fn test_issue_16() {
928     test_html(b"<ul><li><!----></li></ul>", "", 10);
929 }
930 
931 #[test]
932 fn test_pre_br() {
933     test_html(
934         b"<pre>Foo<br>Bar</pre>",
935         r#"Foo
936 Bar
937 "#,
938         10,
939     );
940 }
941 
942 #[test]
943 fn test_pre_emptyline() {
944     test_html(br#"<pre>X<span id="i"> </span></pre>"#, "X  \n", 10);
945 }
946 
947 #[test]
948 fn test_link_id_longline() {
949     test_html(
950         br#"<a href="foo" id="i">quitelongline</a>"#,
951         r#"[quitelong
952 line][1]
953 
954 [1] foo
955 "#,
956         10,
957     );
958 }
959 
960 #[test]
961 fn test_dl() {
962     test_html(
963         br#"<dl><dt>Foo</dt><dd>Definition of foo</dd></dl>"#,
964         r#"*Foo*
965   Definition of foo
966 "#,
967         40,
968     );
969 }
970 
971 #[test]
972 fn test_s() {
973     test_html(
974         br#"Hi <s>you</s>thee!"#,
975         "Hi y\u{336}o\u{336}u\u{336}thee!\n",
976         40,
977     );
978 }
979 
980 #[test]
981 fn test_multi_parse() {
982     let html: &[u8] = b"one two three four five six seven eight nine ten eleven twelve thirteen \
983                         fourteen fifteen sixteen seventeen";
984     let tree = parse(html);
985     assert_eq!(
986         "one two three four five six seven eight nine ten eleven twelve thirteen fourteen\n\
987          fifteen sixteen seventeen\n",
988         tree.clone().render_plain(80).into_string()
989     );
990     assert_eq!(
991         "one two three four five six seven eight nine ten eleven twelve\n\
992          thirteen fourteen fifteen sixteen seventeen\n",
993         tree.clone().render_plain(70).into_string()
994     );
995     assert_eq!(
996         "one two three four five six seven eight nine ten\n\
997          eleven twelve thirteen fourteen fifteen sixteen\n\
998          seventeen\n",
999         tree.clone().render_plain(50).into_string()
1000     );
1001 }
1002 
1003 #[test]
1004 fn test_read_rich() {
1005     let html: &[u8] = b"<strong>bold</strong>";
1006     let lines = parse(html).render_rich(80).into_lines();
1007     let tag = vec![RichAnnotation::Strong];
1008     let line = TaggedLine::from_string("*bold*".to_owned(), &tag);
1009     assert_eq!(vec![line], lines);
1010 }
1011 
1012 #[test]
1013 fn test_read_custom() {
1014     let html: &[u8] = b"<strong>bold</strong>";
1015     let lines = parse(html).render(80, TrivialDecorator::new()).into_lines();
1016     let tag = vec![()];
1017     let line = TaggedLine::from_string("bold".to_owned(), &tag);
1018     assert_eq!(vec![line], lines);
1019 }
1020 
1021 #[test]
1022 fn test_pre_rich() {
1023     use RichAnnotation::*;
1024     assert_eq!(
1025         crate::parse("<pre>test</pre>".as_bytes())
1026             .render_rich(100)
1027             .into_lines(),
1028         [TaggedLine::from_string(
1029             "test".into(),
1030             &vec![Preformat(false)]
1031         )]
1032     );
1033 
1034     assert_eq!(
1035         crate::parse("<pre>testlong</pre>".as_bytes())
1036             .render_rich(4)
1037             .into_lines(),
1038         [
1039             TaggedLine::from_string("test".into(), &vec![Preformat(false)]),
1040             TaggedLine::from_string("long".into(), &vec![Preformat(true)])
1041         ]
1042     );
1043 }
1044