4 # Praat script handling configuration page
6 # SpeakGoodChinese: Config.praat loads the code needed for the
7 # settings and the Settings page of SpeakGoodChinese.
9 # Copyright (C) 2007-2010 R.J.J.H. van Son
10 # The SpeakGoodChinese team are:
11 # Guangqin Chen, Zhonyan Chen, Stefan de Koning, Eveline van Hagen,
12 # Rob van Son, Dennis Vierkant, David Weenink
14 # This program is free software; you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation; either version 2 of the License, or
17 # (at your option) any later version.
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
29 ###############################################################
31 # Button Drawing Routines
33 ###############################################################
35 procedure DrawCredits .color$ .x .y .size
38 call adjustFontSizeOnHeight 24 '.lineheight'
39 .currentFontSize = adjustFontSizeOnHeight.newFontSize
40 demo Paint circle... {0.2,0.2,0.8} '.x' '.y' '.size'
42 demo Text special... '.x' centre '.y' half Times '.currentFontSize' 0 i
45 call set_font_size 'defaultFontSize'
48 procedure DrawDeleteList .color$ .x .y .size
54 demo Paint rectangle... White '.leftX' '.rightX' '.botY' '.topY'
57 .displayWordList$ = replace_regex$(wordlistName$, "[_]", " ", 0)
60 .maxWidth = (.rightX - .leftX)
61 .currentFontSize = defaultFontSize
62 call adjustFontSizeOnWidth '.currentFontSize' '.maxWidth' '.displayWordList$'
63 .currentFontSize = adjustFontSizeOnWidth.newFontSize
64 call set_font_size '.currentFontSize'
66 demo Text... '.x' Centre '.botY' Bottom '.displayWordList$'
69 call set_font_size 'defaultFontSize'
72 procedure DrawLogging .color$ .x .y .size
76 .color$ = "{0.5,0.5,1}"
80 demo Paint circle... '.color$' '.x' '.y' '.size'
83 ###############################################################
85 # Obligatory button Drawing Routines
87 # These MUST be defined
89 ###############################################################
91 procedure DrawReturn .color$ .x .y .size
92 call DrawConfig '.color$' '.x' '.y' '.size'
95 # Set the correct button states after redrawing hte window
96 procedure setConfigButtons
97 call Draw_button 'config$' Lang_'language$' 2
98 call Draw_button 'config$' Register_'register' 2
100 call Draw_button 'config$' DisplayNumbers 2
103 call Draw_button 'config$' DisplayPinyin 2
106 call Draw_button 'config$' DisplayChar 2
109 call Draw_button 'config$' Shuffle 2
112 call Draw_button 'config$' SndExample 2
115 call Draw_button 'config$' Precision 2
117 call Draw_button 'config$' Input'soundInput$' 2
118 # Handle logging buttons with forced button draw
119 if fileReadable("'preferencesLogDir$'/logPerformance.txt")
120 call Draw_button 'config$' +!Logging 'logPerformance'
124 ###############################################################
126 # Button Processing Routines
128 ###############################################################
130 procedure processConfigShuffle .clickX .clickY .pressed$
133 shuffleLists = not shuffleLists
134 .displayButton = 2*shuffleLists
135 call Draw_button '.table$' '.label$' '.displayButton'
138 procedure processConfigSndExample .clickX .clickY .pressed$
140 .label$ = "SndExample"
141 useSoundExample = not useSoundExample
142 .displayButton = 2*useSoundExample
143 call Draw_button '.table$' '.label$' '.displayButton'
146 procedure processConfigPrecision .clickX .clickY .pressed$
148 .label$ = "Precision"
156 call Draw_button '.table$' '.label$' '.displayButton'
159 procedure processConfigDisplayPinyin .clickX .clickY .pressed$
161 .label$ = "DisplayPinyin"
162 displayPinyin = not displayPinyin
163 .displayButton = 2*displayPinyin
164 call Draw_button '.table$' '.label$' '.displayButton'
167 procedure processConfigDisplayChar .clickX .clickY .pressed$
169 .label$ = "DisplayChar"
170 displayChar = not displayChar
171 .displayButton = 2*displayChar
172 call Draw_button 'table$' '.label$' '.displayButton'
175 procedure processConfigDisplayNumbers .clickX .clickY .pressed$
177 .label$ = "DisplayNumbers"
178 displayNumbers = not displayNumbers
179 .displayButton = 2*displayNumbers
180 call Draw_button 'table$' '.label$' '.displayButton'
183 procedure processConfigLang .language$ .clickX .clickY .pressed$
185 .label$ = "Lang_'.language$'"
186 call processLanguageCodes '.table$' '.label$'
189 procedure processConfigLang_EN .clickX .clickY .pressed$
192 call processLanguageCodes '.table$' '.label$'
195 procedure processConfigLang_NL .clickX .clickY .pressed$
198 call processLanguageCodes '.table$' '.label$'
201 procedure processConfigInputMicrophone .clickX .clickY .pressed$
203 .label$ = "InputMicrophone"
204 call Draw_button '.table$' Input'soundInput$' 0
205 call Draw_button '.table$' '.label$' 2
206 .numChars = length(.label$) - length("Input")
207 soundInput$ = right$(.label$, .numChars)
210 procedure processConfigInputLine .clickX .clickY .pressed$
212 .label$ = "InputLine"
213 call Draw_button '.table$' Input'soundInput$' 0
214 call Draw_button '.table$' '.label$' 2
215 .numChars = length(.label$) - length("Input")
216 soundInput$ = right$(.label$, .numChars)
219 procedure processConfigRegister .register .clickX .clickY .pressed$
221 .label$ = "Register_'.register'"
222 call setRegisterFromLabel '.table$' '.label$'
225 procedure processConfigRegister_350 .clickX .clickY .pressed$
227 .label$ = "Register_350"
228 call setRegisterFromLabel '.table$' '.label$'
231 procedure processConfigRegister_300 .clickX .clickY .pressed$
233 .label$ = "Register_300"
234 call setRegisterFromLabel '.table$' '.label$'
237 procedure processConfigRegister_250 .clickX .clickY .pressed$
239 .label$ = "Register_250"
240 call setRegisterFromLabel '.table$' '.label$'
243 procedure processConfigRegister_249 .clickX .clickY .pressed$
245 .label$ = "Register_249"
246 call setRegisterFromLabel '.table$' '.label$'
249 procedure processConfigRegister_180 .clickX .clickY .pressed$
251 .label$ = "Register_180"
252 call setRegisterFromLabel '.table$' '.label$'
255 procedure processConfigRegister_150 .clickX .clickY .pressed$
257 .label$ = "Register_150"
258 call setRegisterFromLabel '.table$' '.label$'
261 procedure setRegisterFromLabel .table$ .label$
262 call Draw_button '.table$' Register_'register' 0
263 call Draw_button '.table$' '.label$' 2
264 # Someone might have to use more than 3 chars for the register code
265 .numChars = length(.label$) - length("Register_")
266 .registerText$ = right$(.label$, .numChars)
267 register = '.registerText$'
270 procedure processConfigDeleteWordlist .clickX .clickY .pressed$
272 .label$ = "DeleteWordlist"
273 call findLabel '.table$' !'.label$'
275 select Table '.table$'
276 .alertText$ = Get value... 'findLabel.row' Text
277 .confirmKey$ = Get value... 'findLabel.row' Key
279 exit Cannot find delete directive: '.table$' !'.label$'
281 call Draw_button '.table$' '.label$' 2
282 alertText$ = .alertText$
283 call Draw_button '.table$' '.label$' 3
285 # Wait for confirmation
287 if demoInput(.confirmKey$)
288 .deleteWordListDir$ = wordlistName$
289 call load_word_list "'localWordlistDir$'" 1
290 call removeWordlist '.deleteWordListDir$'
292 call Draw_button '.table$' '.label$' 0
295 procedure processConfigInstallWordlist .clickX .clickY .pressed$
297 .label$ = "InstallWordlist"
298 call Draw_button '.table$' '.label$' 1
299 call sgc2wordlist 'homeDirectory$'
300 call sgc2wordlist 'homeDirectory$'/Downloads
301 call sgc2wordlist 'homeDirectory$'/Desktop
302 call sgc2wordlist 'preferencesDirectory$'/sgc2
303 call Draw_button '.table$' '.label$' 0
306 ###############################################################
308 # Obligatory button Processing Routines
310 # These MUST be defined
312 ###############################################################
314 procedure processConfigReturn .clickX .clickY .pressed$
317 call Draw_button '.table$' '.label$' 1
318 call write_preferences ""
321 procedure processConfigRefresh .clickX .clickY .pressed$
324 call Draw_config_page
327 procedure processConfigCredits .clickX .clickY .pressed$
330 call Draw_button '.table$' '.label$' 1
333 call Draw_button '.table$' '.label$' 0
335 call Draw_config_page
338 procedure processConfigHelp .clickX .clickY .pressed$
341 call help_loop '.table$' Draw_config_page
344 ###############################################################
346 # Miscelaneous supporting code
348 ###############################################################
349 # Word lists: It is a VERY good idea to make sure that word-lists
351 procedure load_word_list .localdir$ .relnumber
352 # Remove old word list
354 select Table 'wordlist$'
356 call wipeArea 'wipeWordlistArea$'
360 # Create Table that will recieve the wordlists and directories
361 Create Table with column names... AllWordLists 0 Name Directory
362 .currentWordlistRow = 0
364 # Start with the word lists in the distribution, unless the local directory exists!
365 if not fileReadable(.localdir$)
366 call CreateCreateWordlists
367 select Table CreateWordlists
368 .numLists = Get number of rows
370 select Table CreateWordlists
371 .currentName$ = Get value... '.i' Name
372 .currentDirectory$ = "*call Create'.currentName$'"
373 select Table AllWordLists
375 .currentWordlistRow = Get number of rows
376 Set string value... '.currentWordlistRow' Name '.currentName$'
377 .currentDirectory$ = "*call Create'.currentName$'"
378 Set string value... '.currentWordlistRow' Directory '.currentDirectory$'
380 select Table CreateWordlists
384 # First the clobal word lists
385 if fileReadable(globalwordlists$)
386 Create Strings as directory list... WordList 'globalwordlists$'
387 .numLists = Get number of strings
389 select Strings WordList
390 .currentName$ = Get string... '.i'
391 select Table AllWordLists
393 .currentWordlistRow = Get number of rows
394 Set string value... '.currentWordlistRow' Name '.currentName$'
395 .currentDirectory$ = globalwordlists$+"/"+.currentName$
396 Set string value... '.currentWordlistRow' Directory '.currentDirectory$'
398 select Strings WordList
402 # Now the preferences word lists
403 if fileReadable(sgc2wordlists$)
404 Create Strings as directory list... WordList 'sgc2wordlists$'
405 .numLists = Get number of strings
407 select Strings WordList
408 .currentName$ = Get string... '.i'
409 select Table AllWordLists
411 .currentWordlistRow = Get number of rows
412 Set string value... '.currentWordlistRow' Name '.currentName$'
413 .currentDirectory$ = sgc2wordlists$+"/"+.currentName$
414 Set string value... '.currentWordlistRow' Directory '.currentDirectory$'
416 select Strings WordList
420 # Finally, the local word lists
421 if fileReadable(.localdir$)
422 Create Strings as directory list... WordList '.localdir$'
423 .numLists = Get number of strings
425 select Strings WordList
426 .currentName$ = Get string... '.i'
427 select Table AllWordLists
429 .currentWordlistRow = Get number of rows
430 Set string value... '.currentWordlistRow' Name '.currentName$'
431 .currentDirectory$ = .localdir$+"/"+.currentName$
432 Set string value... '.currentWordlistRow' Directory '.currentDirectory$'
434 select Strings WordList
438 # Get the position of the current word list
439 select Table AllWordLists
441 .numLists = Get number of rows
442 if wordlistName$ <> ""
443 select Table AllWordLists
444 .currentNumber = Search column... Name 'wordlistName$'
446 wordlistNum = .currentNumber + .relnumber
447 if wordlistNum > .numLists
449 elsif wordlistNum < 1
450 wordlistNum = .numLists
452 select Table AllWordLists
453 wordlistName$ = Get value... 'wordlistNum' Name
454 .dirWordlistName$ = Get value... 'wordlistNum' Directory
455 .dirString$ = replace_regex$(.dirWordlistName$, "[ ]", "&", 0)
457 # Read in full tables
458 if fileReadable("'.dirString$'/wordlist.Table")
459 Read from file... '.dirString$'/wordlist.Table
460 Rename... 'wordlistName$'
461 # Praat wil change the name if it feels like it
462 wordlist$ = selected$("Table")
463 # Handle (legacy) simple word lists
464 elsif fileReadable("'.dirString$'/wordlist.txt")
465 Create Table with column names... "'wordlistName$'" 0 Pinyin Character Sound
466 wordlist$ = selected$("Table")
467 Read Strings from raw text file... '.dirString$'/wordlist.txt
468 Rename... RawWordList
469 .numWordStrings = Get number of strings
470 for .i to .numWordStrings
471 select Strings RawWordList
472 .currentLine$ = Get string... '.i'
473 .currentPinyin$ = extractWord$(.currentLine$, "")
474 if length(.currentLine$) > length(.currentPinyin$)+1
475 .currentFile$ = right$(.currentLine$, length(.currentPinyin$)+1)
476 elsif fileReadable("'.dirString$'/'.currentPinyin$'.spx")
477 .currentFile$ = .currentPinyin$+".spx"
478 elsif fileReadable("'.dirString$'/'.currentPinyin$'.flac")
479 .currentFile$ = .currentPinyin$+".flac"
480 elsif fileReadable("'.dirString$'/'.currentPinyin$'.wav")
481 .currentFile$ = .currentPinyin$+".wav"
482 elsif fileReadable("'.dirString$'/'.currentPinyin$'.mp3")
483 .currentFile$ = .currentPinyin$+".mp3"
487 select Table 'wordlist$'
489 Set string value... '.i' Pinyin '.currentPinyin$'
490 Set string value... '.i' Character -
491 Set string value... '.i' Sound '.currentFile$'
493 select Strings RawWordList
496 select Table 'wordlist$'
497 elsif fileReadable(.dirString$)
498 Create Table with column names... "'wordlistName$'" 0 Pinyin Character Sound
499 wordlist$ = selected$("Table")
500 Create Strings as file list... RawWordList '.dirString$'/*
501 .numWordStrings = Get number of strings
503 for .j to .numWordStrings
504 select Strings RawWordList
505 .currentLine$ = Get string... '.j'
506 .currentFile$ = extractWord$(.currentLine$, "")
507 if index_regex(.currentFile$, "\.(spx|flac|wav|mp3)")
508 .currentPinyin$ = left$(.currentFile$, index(.currentFile$, ".")-1)
509 select Table 'wordlist$'
512 Set string value... '.i' Pinyin '.currentPinyin$'
513 Set string value... '.i' Character -
514 Set string value... '.i' Sound '.currentFile$'
517 select Strings RawWordList
520 select Table 'wordlist$'
521 elsif startsWith(.dirString$, "*call ")
522 .callProcedure$ = right$(.dirString$, length(.dirString$)-1)
524 wordlist$ = selected$("Table")
527 numberOfWords = Get number of rows
533 select Table AllWordLists
536 # There were no Word Lists
539 wordlistName$ = "No Word Lists available"
541 Create Table with column names... "'wordlistName$'" 0 Pinyin Character Sound
542 wordlist$ = selected$("Table")
546 Set string value... '.i' Pinyin ni3hao3
547 Set string value... '.i' Character -
548 Set string value... '.i' Sound -
551 Set string value... '.i' Pinyin xie4xie0
552 Set string value... '.i' Character -
553 Set string value... '.i' Sound -
556 Set string value... '.i' Pinyin zai4jian4
557 Set string value... '.i' Character -
558 Set string value... '.i' Sound -
559 numberOfWords = Get number of rows
562 call set_window_title 'buttons$' 'wordlistName$'
565 procedure display_word_list_name
569 .displayWordList$ = replace_regex$(wordlistName$, "[_]", " ", 0)
570 call wipeArea 'wipeWordlistArea$'
571 call adjustFontSizeOnHeight 'defaultFontSize' 5
572 .currentFontSize = adjustFontSizeOnHeight.newFontSize
575 demo Text special... '.xtext' Centre '.ytext' Bottom Helvetica '.currentFontSize' 0 '.displayWordList$'
578 call set_font_size 'defaultFontSize'
581 procedure write_word_list
583 call draw_tone_contour
585 # Write current Pinyin text
586 call display_text Black
588 # Write the current word list name
589 call display_word_list_name
592 procedure start_logging
593 if fileReadable("'preferencesLogDir$'/logPerformance.txt")
594 .logDirectory$ < 'preferencesLogDir$'/logPerformance.txt
595 .logDirectory$ = extractWord$(.logDirectory$, "")
596 if .logDirectory$ = "" or not fileReadable(.logDirectory$)
597 .logDirectory$ = "'preferencesDirectory$'/sgc2/log"
599 createDirectory("'.logDirectory$'/sgc2log")
600 currentLogDirectory$ = "'.logDirectory$'/sgc2log/log'logtimeStamp$'"
601 createDirectory(currentLogDirectory$)
602 if not fileReadable("'currentLogDirectory$'/wordlist.Table")
603 .headerLine$ = "Pinyin'tab$'Character'tab$'Sound'newline$'"
604 .headerLine$ > 'currentLogDirectory$'/wordlist.Table
611 procedure log_performance .recordedSound$ .register .precision .pinyin$ .choice$
613 .currentDate$ = date$()
614 .timeStamp$ = replace_regex$(.currentDate$, "[^a-zA-Z0-9\-_]", "-", 0)
615 .choiceText$ = replace_regex$(.choice$, "[^a-zA-Z0-9\-_]", "-", 0)
617 if logPerformance and fileReadable("'preferencesLogDir$'/logPerformance.txt")
618 .outfilename$ = .pinyin$+"_"+.choice$+"_'.register'_"+.timeStamp$+".wav"
619 .logtext$ = .pinyin$+tab$+.choice$+tab$+"'.register'Hz"+tab$+.currentDate$+tab$+.outfilename$+newline$
621 fileappend 'currentLogDirectory$'/logFile.txt '.logtext$'
623 fileappend 'currentLogDirectory$'/wordlist.Table '.pinyin$''tab$''.choice$''tab$''.outfilename$''newline$'
625 select Sound 'recordedSound$'
626 Write to WAV file... 'currentLogDirectory$'/'.outfilename$'
630 procedure paint_logging_light
632 .row = Search column... Label !Logging
634 exit Button Table Config does not have a row with label !Logging
637 .leftX = Get value... '.row' LeftX
638 .rightX = Get value... '.row' RightX
639 .lowY = Get value... '.row' LowY
640 .highY = Get value... '.row' HighY
641 .buttonColor$ = Get value... '.row' Color
642 .centerX = (.leftX + .rightX)/2
643 .centerY = (.lowY + .highY)/2
644 .radius = (.highY - .lowY )/(4*2)
645 .wipeRadius = 1.1*.radius
646 if logPerformance and fileReadable("'preferencesLogDir$'/logPerformance.txt")
647 demo Paint circle... White '.centerX' '.centerY' '.wipeRadius'
648 demo Paint circle... '.buttonColor$' '.centerX' '.centerY' '.radius'
651 demo Paint circle... White '.centerX' '.centerY' '.wipeRadius'
656 # Uninstall word lists
657 procedure removeWordlist .deletedWordlistName$
659 if fileReadable("'preferencesDirectory$'/sgc2/wordlists/'.deletedWordlistName$'")
660 .targetDir$ = "'preferencesDirectory$'/sgc2/wordlists/'.deletedWordlistName$'"
661 elsif fileReadable("'localWordlistDir$'/'.deletedWordlistName$'")
662 .targetDir$ = "'localWordlistDir$'/'.deletedWordlistName$'"
664 Create Strings as file list... DeleteList '.targetDir$'/*
665 .numdeleteFiles = Get number of strings
666 for .i to .numdeleteFiles
667 .file$ = Get string... '.i'
668 deleteFile("'.targetDir$'/'.file$'")
670 deleteFile("'.targetDir$'")
674 procedure sgc2wordlist .sourceDir$
675 if startsWith(.sourceDir$, "preferencesDirectory$")
676 .sourceDir$ = replace$(.sourceDir$, "preferencesDirectory$", preferencesDirectory$)
679 .targetDirectory$ = "'preferencesDirectory$'/sgc2/wordlists"
680 if fileReadable(.sourceDir$)
681 Create Strings as file list... PackageList '.sourceDir$'/*.sgc
682 .numFiles = Get number of strings
684 select Strings PackageList
685 .file$ = Get string... '.i'
686 .dirname$ = left$(.file$, index(.file$, ".sgc")-1)
687 .wordlistDirectory$ = .targetDirectory$+"/"+.dirname$
688 if not (fileReadable(.dirname$) or fileReadable(.wordlistDirectory$))
689 createDirectory(.wordlistDirectory$)
691 system cp ''.sourceDir$'/'.file$'' ''.wordlistDirectory$'/'
692 system cd ''.wordlistDirectory$'';unzip ''.file$'';rm ''.file$''
696 # printline '.dirname$' already exists
700 select Strings PackageList
706 procedure write_credits
712 .referenceText$ = "organisational, and financial support from the staff and board of the Digitale Universiteit."
713 .creditsFontSize = 12
715 # Adapt size of button to length of text
716 .maxWidth = (.xright - .xleft) - 3
717 call adjustFontSizeOnWidth '.creditsFontSize' '.maxWidth' '.referenceText$'
718 .creditsFontSize = adjustFontSizeOnWidth.newFontSize
719 if adjustFontSizeOnWidth.diff > 0
720 .xright += adjustFontSizeOnWidth.diff/4
721 .xleft -= 3*adjustFontSizeOnWidth.diff/4
723 call set_font_size '.creditsFontSize'
726 demo Colour... {0.5,0.5,1}
727 demo Paint rectangle... {0.9,0.9,1} '.xleft' '.xright' '.ylow' '.yhigh'
728 demo Draw rectangle... '.xleft' '.xright' '.ylow' '.yhigh'
729 demo Line width... 'defaultLineWidth'
733 .ytext = .yhigh - 2 - .dy
734 demo Text... '.xleft' Left '.ytext' Bottom SpeakGoodChinese version 2.0
736 demo Text... '.xleft' Left '.ytext' Bottom For more information, visit our website: http://www.speakgoodchinese.org
738 demo Text... '.xleft' Left '.ytext' Bottom Based on Praat (http://www.praat.org)
740 demo Text... '.xleft' Left '.ytext' Bottom SpeakGoodChinese was supported by grant 6046 from the Digitale Universiteit
742 demo Text... '.xleft' Left '.ytext' Bottom The SpeakGoodChinese Team
744 demo Text... '.xleft' Left '.ytext' Bottom * Guanqin Chen (HRO) - Founder and project manager, Language and Teaching
746 demo Text... '.xleft' Left '.ytext' Bottom * Zongyan Chen (HvA) - Language and Teaching
748 demo Text... '.xleft' Left '.ytext' Bottom * Eveline van Hagen (Fontys) - Language and Teaching
750 demo Text... '.xleft' Left '.ytext' Bottom * Stefan de Konink (UvA) - Lead programmer, User Interface
752 demo Text... '.xleft' Left '.ytext' Bottom * Lifeng Liu (HRO) - Language assistant
754 demo Text... '.xleft' Left '.ytext' Bottom * Rob van Son (UvA) - Coordinator technical work, Speech technology, demo GUI
756 demo Text... '.xleft' Left '.ytext' Bottom * Dennis Vierkant (UT) - User Interface and Language
758 demo Text... '.xleft' Left '.ytext' Bottom * David Weenink (UvA) - Praat programming, Algorithms We would like to thank
760 demo Text... '.xleft' Left '.ytext' Bottom We would like to thank Paul Boersma (UvA) for his help with Praat linking
762 demo Text... '.xleft' Left '.ytext' Bottom and Tristian van Berkom for additional help with the localization code.
764 demo Text... '.xleft' Left '.ytext' Bottom J.E. Raaijmakers, R. van Rijsselt and S. Verhagen for feedback on the GUI and
766 demo Text... '.xleft' Left '.ytext' Bottom Praat library integration on Windows.
768 demo Text... '.xleft' Left '.ytext' Bottom We are very grateful for all the practical, organisational, and financial
770 demo Text... '.xleft' Left '.ytext' Bottom support from the staff and board of the Digitale Universiteit.
773 call set_font_size 'defaultFontSize'