Give a more informative exception on SubRip parse failures.
[libsub.git] / test / subrip_reader_test.cc
1 /*
2     Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "subrip_reader.h"
21 #include "subtitle.h"
22 #include "test.h"
23 #include "collect.h"
24 #include <boost/test/unit_test.hpp>
25 #include <boost/filesystem.hpp>
26 #include <cmath>
27 #include <iostream>
28 #include <cstdio>
29
30 using std::list;
31 using std::cerr;
32 using std::vector;
33 using std::fabs;
34
35 /* Test reading of a Subrip file */
36 BOOST_AUTO_TEST_CASE (subrip_reader_test)
37 {
38         FILE* f = fopen ("test/data/test.srt", "r");
39         sub::SubripReader reader (f);
40         fclose (f);
41         list<sub::Subtitle> subs = sub::collect<std::list<sub::Subtitle> > (reader.subtitles ());
42
43         list<sub::Subtitle>::iterator i = subs.begin ();
44
45
46         /* First subtitle */
47
48         BOOST_CHECK (i != subs.end ());
49         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 0, 41, 90));
50         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 0, 42, 210));
51
52         list<sub::Line>::iterator j = i->lines.begin ();
53         BOOST_CHECK (j != i->lines.end ());
54         BOOST_CHECK_EQUAL (j->blocks.size(), 1);
55         sub::Block b = j->blocks.front ();
56         BOOST_CHECK_EQUAL (b.text, "This is a subtitle");
57         /* No font is specified by subrip, so none should be seen here */
58         BOOST_CHECK (!b.font);
59         BOOST_CHECK (!b.font_size.specified());
60         BOOST_CHECK_EQUAL (b.bold, false);
61         BOOST_CHECK_EQUAL (b.italic, false);
62         BOOST_CHECK_EQUAL (b.underline, false);
63         BOOST_CHECK_EQUAL (j->vertical_position.line.get(), 0);
64         BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
65         ++j;
66
67         BOOST_CHECK (j != i->lines.end ());
68         BOOST_CHECK_EQUAL (j->blocks.size(), 1);
69         b = j->blocks.front ();
70         BOOST_CHECK_EQUAL (b.text, "and that's a line break");
71         /* No font is specified by subrip, so none should be seen here */
72         BOOST_CHECK (!b.font);
73         BOOST_CHECK (!b.font_size.specified());
74         BOOST_CHECK_EQUAL (b.bold, false);
75         BOOST_CHECK_EQUAL (b.italic, false);
76         BOOST_CHECK_EQUAL (b.underline, false);
77         BOOST_CHECK_EQUAL (j->vertical_position.line.get(), 1);
78         BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
79         ++i;
80
81
82         /* Second subtitle */
83
84         BOOST_CHECK (i != subs.end ());
85         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 1, 10));
86         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 2, 100));
87
88         BOOST_CHECK_EQUAL (i->lines.size(), 1);
89         sub::Line l = i->lines.front ();
90         BOOST_CHECK_EQUAL (l.blocks.size(), 7);
91         BOOST_CHECK_EQUAL (l.vertical_position.line.get(), 0);
92         BOOST_CHECK_EQUAL (l.vertical_position.reference.get(), sub::TOP_OF_SUBTITLE);
93
94         list<sub::Block>::iterator k = l.blocks.begin ();
95
96         BOOST_CHECK (k != l.blocks.end ());
97         BOOST_CHECK_EQUAL (k->text, "This is some ");
98         /* No font is specified by subrip, so none should be seen here */
99         BOOST_CHECK (!b.font);
100         BOOST_CHECK (!b.font_size.specified());
101         BOOST_CHECK_EQUAL (k->bold, false);
102         BOOST_CHECK_EQUAL (k->italic, false);
103         BOOST_CHECK_EQUAL (k->underline, false);
104         ++k;
105
106         BOOST_CHECK (k != l.blocks.end ());
107         BOOST_CHECK_EQUAL (k->text, "bold");
108         /* No font is specified by subrip, so none should be seen here */
109         BOOST_CHECK (!b.font);
110         BOOST_CHECK (!b.font_size.specified());
111         BOOST_CHECK_EQUAL (k->bold, true);
112         BOOST_CHECK_EQUAL (k->italic, false);
113         BOOST_CHECK_EQUAL (k->underline, false);
114         ++k;
115
116         BOOST_CHECK (k != l.blocks.end ());
117         BOOST_CHECK_EQUAL (k->text, " and some ");
118         /* No font is specified by subrip, so none should be seen here */
119         BOOST_CHECK (!b.font);
120         BOOST_CHECK (!b.font_size.specified());
121         BOOST_CHECK_EQUAL (k->bold, false);
122         BOOST_CHECK_EQUAL (k->italic, false);
123         BOOST_CHECK_EQUAL (k->underline, false);
124         ++k;
125
126         BOOST_CHECK (k != l.blocks.end ());
127         BOOST_CHECK_EQUAL (k->text, "bold italic");
128         /* No font is specified by subrip, so none should be seen here */
129         BOOST_CHECK (!b.font);
130         BOOST_CHECK (!b.font_size.specified());
131         BOOST_CHECK_EQUAL (k->bold, true);
132         BOOST_CHECK_EQUAL (k->italic, true);
133         BOOST_CHECK_EQUAL (k->underline, false);
134         ++k;
135
136         BOOST_CHECK (k != l.blocks.end ());
137         BOOST_CHECK_EQUAL (k->text, " and some ");
138         /* No font is specified by subrip, so none should be seen here */
139         BOOST_CHECK (!b.font);
140         BOOST_CHECK (!b.font_size.specified());
141         BOOST_CHECK_EQUAL (k->bold, false);
142         BOOST_CHECK_EQUAL (k->italic, false);
143         BOOST_CHECK_EQUAL (k->underline, false);
144         ++k;
145
146         BOOST_CHECK (k != l.blocks.end ());
147         BOOST_CHECK_EQUAL (k->text, "underlined");
148         /* No font is specified by subrip, so none should be seen here */
149         BOOST_CHECK (!b.font);
150         BOOST_CHECK (!b.font_size.specified());
151         BOOST_CHECK_EQUAL (k->bold, false);
152         BOOST_CHECK_EQUAL (k->italic, false);
153         BOOST_CHECK_EQUAL (k->underline, true);
154         ++k;
155
156         BOOST_CHECK (k != l.blocks.end ());
157         BOOST_CHECK_EQUAL (k->text, ".");
158         /* No font is specified by subrip, so none should be seen here */
159         BOOST_CHECK (!b.font);
160         BOOST_CHECK (!b.font_size.specified());
161         BOOST_CHECK_EQUAL (k->bold, false);
162         BOOST_CHECK_EQUAL (k->italic, false);
163         BOOST_CHECK_EQUAL (k->underline, false);
164         ++k;
165
166         BOOST_CHECK (k == l.blocks.end ());
167 }
168
169 /* Test reading of another Subrip file */
170 BOOST_AUTO_TEST_CASE (subrip_reader_test2)
171 {
172         FILE* f = fopen ("test/data/test2.srt", "r");
173         sub::SubripReader reader (f);
174         fclose (f);
175         list<sub::Subtitle> subs = sub::collect<list<sub::Subtitle> > (reader.subtitles ());
176
177         list<sub::Subtitle>::const_iterator i = subs.begin();
178
179         BOOST_CHECK (i != subs.end ());
180         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 49, 200));
181         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 52, 351));
182         BOOST_CHECK_EQUAL (i->lines.size(), 2);
183         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "This is a subtitle, and it goes ");
184         BOOST_CHECK_EQUAL (i->lines.back().blocks.front().text, "over two lines.");
185
186         ++i;
187         BOOST_CHECK (i != subs.end ());
188         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 52, 440));
189         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 54, 351));
190         BOOST_CHECK_EQUAL (i->lines.size(), 1);
191         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "We have emboldened this");
192         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().bold, true);
193
194         ++i;
195         BOOST_CHECK (i != subs.end ());
196         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 54, 440));
197         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 56, 590));
198         BOOST_CHECK_EQUAL (i->lines.size(), 1);
199         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "And italicised this.");
200         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().italic, true);
201
202         ++i;
203         BOOST_CHECK (i != subs.end ());
204         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 56, 680));
205         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 58, 955));
206         BOOST_CHECK_EQUAL (i->lines.size(), 1);
207         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Shall I compare thee to a summers' day?");
208
209         ++i;
210         BOOST_CHECK (i != subs.end ());
211         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 2, 0, 840));
212         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 2, 3, 400));
213         BOOST_CHECK_EQUAL (i->lines.size(), 1);
214         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Is this a dagger I see before me?");
215
216         ++i;
217         BOOST_CHECK (i != subs.end ());
218         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 3, 54, 560));
219         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 3, 56, 471));
220         BOOST_CHECK_EQUAL (i->lines.size(), 1);
221         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Hello world.");
222
223         ++i;
224         BOOST_CHECK (i != subs.end ());
225         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 4, 50, 123));
226         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 4, 55, 23));
227         BOOST_CHECK_EQUAL (i->lines.size(), 2);
228         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().text, "Some italics over");
229         BOOST_CHECK_EQUAL (i->lines.front().blocks.front().italic, true);
230         BOOST_CHECK_EQUAL (i->lines.back().blocks.front().text, "multiple lines");
231         BOOST_CHECK_EQUAL (i->lines.back().blocks.front().italic, true);
232
233         ++i;
234         BOOST_CHECK (i == subs.end ());
235 }
236
237 /** Test SubripReader::convert_line */
238 BOOST_AUTO_TEST_CASE (subrip_reader_convert_line_test)
239 {
240         sub::SubripReader r;
241
242         sub::RawSubtitle rs;
243         r.convert_line ("Hello world", rs);
244         BOOST_CHECK_EQUAL (r._subs.size(), 1);
245         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
246         r._subs.clear ();
247
248         rs = sub::RawSubtitle();
249         r.convert_line ("<b>Hello world</b>", rs);
250         BOOST_CHECK_EQUAL (r._subs.size(), 1);
251         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
252         BOOST_CHECK_EQUAL (r._subs.front().bold, true);
253         r._subs.clear ();
254
255         rs = sub::RawSubtitle();
256         r.convert_line ("<i>Hello world</i>", rs);
257         BOOST_CHECK_EQUAL (r._subs.size(), 1);
258         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
259         BOOST_CHECK_EQUAL (r._subs.front().italic, true);
260         r._subs.clear ();
261
262         rs = sub::RawSubtitle();
263         r.convert_line ("<u>Hello world</u>", rs);
264         BOOST_CHECK_EQUAL (r._subs.size(), 1);
265         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
266         BOOST_CHECK_EQUAL (r._subs.front().underline, true);
267         r._subs.clear ();
268
269         rs = sub::RawSubtitle();
270         r.convert_line ("{b}Hello world{/b}", rs);
271         BOOST_CHECK_EQUAL (r._subs.size(), 1);
272         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
273         BOOST_CHECK_EQUAL (r._subs.front().bold, true);
274         r._subs.clear ();
275
276         rs = sub::RawSubtitle();
277         r.convert_line ("{i}Hello world{/i}", rs);
278         BOOST_CHECK_EQUAL (r._subs.size(), 1);
279         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
280         BOOST_CHECK_EQUAL (r._subs.front().italic, true);
281         r._subs.clear ();
282
283         rs = sub::RawSubtitle();
284         r.convert_line ("{u}Hello world{/u}", rs);
285         BOOST_CHECK_EQUAL (r._subs.size(), 1);
286         BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world");
287         BOOST_CHECK_EQUAL (r._subs.front().underline, true);
288         r._subs.clear ();
289
290         rs = sub::RawSubtitle();
291         r.convert_line ("<b>This is <i>nesting</i> of subtitles</b>", rs);
292         BOOST_CHECK_EQUAL (r._subs.size(), 3);
293         list<sub::RawSubtitle>::iterator i = r._subs.begin ();
294         BOOST_CHECK_EQUAL (i->text, "This is ");
295         BOOST_CHECK_EQUAL (i->bold, true);
296         BOOST_CHECK_EQUAL (i->italic, false);
297         ++i;
298         BOOST_CHECK_EQUAL (i->text, "nesting");
299         BOOST_CHECK_EQUAL (i->bold, true);
300         BOOST_CHECK_EQUAL (i->italic, true);
301         ++i;
302         BOOST_CHECK_EQUAL (i->text, " of subtitles");
303         BOOST_CHECK_EQUAL (i->bold, true);
304         BOOST_CHECK_EQUAL (i->italic, false);
305         ++i;
306         r._subs.clear ();
307
308         rs = sub::RawSubtitle();
309         r.convert_line ("<font color=\"#ff00ff\">simple color</font>", rs);
310         BOOST_CHECK_EQUAL (r._subs.size(), 1);
311         BOOST_CHECK_EQUAL (r._subs.front().text, "simple color");
312         BOOST_CHECK_EQUAL (r._subs.front().bold, false);
313         BOOST_CHECK_CLOSE (r._subs.front().colour.r, 1, 0.1);
314         BOOST_CHECK (fabs (r._subs.front().colour.g) < 0.01);
315         BOOST_CHECK_CLOSE (r._subs.front().colour.b, 1, 0.1);
316         r._subs.clear ();
317
318         rs = sub::RawSubtitle();
319         r.convert_line ("<font color=\"#ff0000\">some red text <b>in bold</b></font>", rs);
320         BOOST_CHECK_EQUAL (r._subs.size(), 2);
321         i = r._subs.begin ();
322         BOOST_CHECK_EQUAL (i->text, "some red text ");
323         BOOST_CHECK_EQUAL (i->bold, false);
324         BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1);
325         BOOST_CHECK (fabs (i->colour.g) < 0.01);
326         BOOST_CHECK (fabs (i->colour.b) < 0.01);
327         ++i;
328         BOOST_CHECK_EQUAL (i->text, "in bold");
329         BOOST_CHECK_EQUAL (i->bold, true);
330         BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1);
331         BOOST_CHECK (fabs (i->colour.g) < 0.01);
332         BOOST_CHECK (fabs (i->colour.b) < 0.01);
333         r._subs.clear ();
334
335         rs = sub::RawSubtitle();
336         r.convert_line ("<font color=\"#0000ff\">some blue text <b>in bold</b></font>", rs);
337         BOOST_CHECK_EQUAL (r._subs.size(), 2);
338         i = r._subs.begin ();
339         BOOST_CHECK_EQUAL (i->text, "some blue text ");
340         BOOST_CHECK_EQUAL (i->bold, false);
341         BOOST_CHECK (fabs (i->colour.r) < 0.01);
342         BOOST_CHECK (fabs (i->colour.g) < 0.01);
343         BOOST_CHECK_CLOSE (i->colour.b, 1, 0.1);
344         ++i;
345         BOOST_CHECK_EQUAL (i->text, "in bold");
346         BOOST_CHECK_EQUAL (i->bold, true);
347         BOOST_CHECK (fabs (i->colour.r) < 0.01);
348         BOOST_CHECK (fabs (i->colour.g) < 0.01);
349         BOOST_CHECK_CLOSE (i->colour.b, 1, 0.1);
350         r._subs.clear ();
351 }
352
353 /** Test SubripReader::convert_time */
354 BOOST_AUTO_TEST_CASE (subrip_reader_convert_time_test)
355 {
356         sub::SubripReader reader;
357         BOOST_CHECK_EQUAL (reader.convert_time ("00:03:10,500"), sub::Time::from_hms (0, 3, 10, 500));
358         BOOST_CHECK_EQUAL (reader.convert_time ("04:19:51,782"), sub::Time::from_hms (4, 19, 51, 782));
359 }
360
361 static void
362 test (boost::filesystem::path p)
363 {
364         p = private_test / p;
365         FILE* f = fopen (p.string().c_str(), "r");
366         BOOST_CHECK (f);
367         if (!f) {
368                 cerr << p << " not found.\n";
369                 return;
370         }
371         sub::SubripReader r (f);
372         fclose (f);
373 }
374
375 /** Test of reading some typical .srt files */
376 BOOST_AUTO_TEST_CASE (subrip_read_test)
377 {
378         test ("sintel_en.srt");
379         test ("sintel_fr.srt");
380         test ("Fight.Club.1999.720p.BRRip.x264-x0r.srt");
381         test ("EU13.srt");
382 }
383
384 #define SUB_START(f, t) \
385         BOOST_REQUIRE (i != subs.end ()); \
386         BOOST_CHECK_EQUAL (i->from, f); \
387         BOOST_CHECK_EQUAL (i->to, t); \
388         j = i->lines.begin ();
389
390 #define LINE(p)                                                 \
391         BOOST_REQUIRE (j != i->lines.end ()); \
392         BOOST_CHECK (j->vertical_position.line); \
393         BOOST_CHECK_EQUAL (j->vertical_position.line.get(), p); \
394         BOOST_CHECK (j->vertical_position.reference); \
395         BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), sub::TOP_OF_SUBTITLE); \
396         k = j->blocks.begin (); \
397         ++j;
398
399 #define BLOCK(t, f, s, b, i, u) \
400         BOOST_REQUIRE (k != j->blocks.end ()); \
401         BOOST_CHECK_EQUAL (k->text, t); \
402         BOOST_CHECK_EQUAL (k->bold, b); \
403         BOOST_CHECK_EQUAL (k->italic, i); \
404         BOOST_CHECK_EQUAL (k->underline, u); \
405         ++k;
406
407 #define SUB_END() \
408         ++i;
409
410 /** Test reading of another .srt file */
411 BOOST_AUTO_TEST_CASE (subrip_reader_test3)
412 {
413         boost::filesystem::path p = private_test / "DCP-o-matic_test_subs_1.srt";
414         FILE* f = fopen (p.string().c_str(), "r");
415         sub::SubripReader reader (f);
416         fclose (f);
417         list<sub::Subtitle> subs = sub::collect<std::list<sub::Subtitle> > (reader.subtitles ());
418
419         list<sub::Subtitle>::iterator i = subs.begin ();
420         list<sub::Line>::iterator j;
421         list<sub::Block>::iterator k;
422
423         BOOST_REQUIRE (i != subs.end ());
424
425         SUB_START (sub::Time::from_hms (0, 0, 0, 76), sub::Time::from_hms (0, 0, 1, 116));
426         LINE (0);
427         BLOCK ("This line is normal", "Arial", 30, false, false, false);
428         LINE (1);
429         BLOCK ("This line is bold", "Arial", 30, true, false, false);
430         SUB_END ();
431
432         SUB_START (sub::Time::from_hms (0, 0, 1, 206), sub::Time::from_hms (0, 0, 2, 246));
433         LINE (0);
434         BLOCK ("This line is bold", "Arial", 30, true, false, false);
435         LINE (1);
436         BLOCK ("This line is normal", "Arial", 30, false, false, false);
437         SUB_END ();
438
439         SUB_START (sub::Time::from_hms (0, 0, 2, 308), sub::Time::from_hms (0, 0, 3, 380));
440         LINE (0);
441         BLOCK ("This line is bold", "Arial", 30, true, false, false);
442         LINE (1);
443         BLOCK ("This line is italic", "Arial", 30, false, true, false);
444         SUB_END ();
445
446         SUB_START (sub::Time::from_hms (0, 0, 3, 404), sub::Time::from_hms (0, 0, 4, 484));
447         LINE (0);
448         BLOCK ("This line is italic", "Arial", 30, false, true, false);
449         LINE (1);
450         BLOCK ("This line is bold", "Arial", 30, true, false, false);
451         SUB_END ();
452
453         SUB_START (sub::Time::from_hms (0, 0, 4, 519), sub::Time::from_hms (0, 0, 5, 604));
454         LINE (0);
455         BLOCK ("Last three words are ", "Arial", 30, false, false, false);
456         BLOCK ("bold AND italic", "Arial", 30, true, true, false);
457         LINE (1);
458         BLOCK ("Last three words are ", "Arial", 30, false, false, false);
459         BLOCK ("italic AND bold", "Arial", 30, true, true, false);
460         SUB_END ();
461
462         SUB_START (sub::Time::from_hms (0, 0, 5, 628), sub::Time::from_hms (0, 0, 6, 712));
463         LINE (0);
464         BLOCK ("Last three words are ", "Arial", 30, false, false, false);
465         BLOCK ("bold AND italic", "Arial", 30, true, true, false);
466         LINE (1);
467         BLOCK ("First three words", "Arial", 30, true, true, false);
468         BLOCK (" are italic AND bold", "Arial", 30, false, false, false);
469         SUB_END ();
470
471         SUB_START (sub::Time::from_hms (0, 0, 6, 736), sub::Time::from_hms (0, 0, 8, 31));
472         LINE (0);
473         BLOCK ("Last three words are ", "Arial", 30, false, false, false);
474         BLOCK ("bold AND italic", "Arial", 30, true, true, false);
475         LINE (1);
476         BLOCK ("This line is normal", "Arial", 30, false, false, false);
477         SUB_END ();
478
479         SUB_START (sub::Time::from_hms (0, 0, 8, 94), sub::Time::from_hms (0, 0, 9, 211));
480         LINE (0);
481         BLOCK ("Both lines are bold AND italic", "Arial", 30, true, true, false);
482         LINE (1);
483         BLOCK ("Both lines are bold AND italic", "Arial", 30, true, true, false);
484         SUB_END ();
485 }