diff --git a/ZRCola/ZRCola.fbp b/ZRCola/ZRCola.fbp index dd01781..dc4db79 100644 --- a/ZRCola/ZRCola.fbp +++ b/ZRCola/ZRCola.fbp @@ -245,14 +245,14 @@ none - + Load From Icon Resource; char_select.ico; [16; 16] 0 1 Display character selector to select character to insert into text - wxID_INSERT_CHARACTER + wxID_CHARACTER_SELECTOR wxITEM_NORMAL - &Insert Character... - m_menuInsertCharacter + C&haracter Selector... + m_menuCharSelect none F8 @@ -637,6 +637,27 @@ + + Load From Icon Resource; char_select.ico; [24; 24] + 0 + wxID_CHARACTER_SELECTOR + wxITEM_NORMAL + Character Selector + m_toolCharSelect + protected + Display character selector to select character to insert into text + Character Selector + + + + + + + + + + + Load From Icon Resource; send_composed.ico; [24; 24] 0 @@ -1963,6 +1984,15 @@ + + 0 + wxID_TIMER_SAVE + m_timerSave + 1 + 1000 + protected + OnSaveTimer + 0 @@ -2294,7 +2324,7 @@ - + OnIdle @@ -2342,7 +2372,7 @@ 5 wxALL|wxEXPAND - 0 + 1 wxID_ANY &Browse @@ -2402,7 +2432,7 @@ 1 1 - + wxTE_PROCESS_ENTER 0 @@ -2439,7 +2469,7 @@ OnSearchText - + OnSearchEnter @@ -2478,7 +2508,7 @@ wxID_ANY 0 - -1,59 + -1,-1 0 @@ -2492,7 +2522,7 @@ Resizable 1 - + -1,60 0 @@ -2507,7 +2537,7 @@ - + OnCategoriesToggle @@ -2535,7 +2565,7 @@ 5 wxALL|wxEXPAND - 0 + 1 1 1 @@ -2562,8 +2592,8 @@ 0 wxALIGN_CENTRE - 16 - 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35 + 0 + 1 0 @@ -2580,7 +2610,7 @@ 1 ,90,90,-1,70,0 - 1 + 0 0 0 wxID_ANY @@ -2591,10 +2621,10 @@ 0 0 - + 560,-1 0 - + 560,35 1 m_gridResults 1 @@ -2608,22 +2638,22 @@ 0 wxALIGN_CENTRE - 35,35,35,35,35,35,35 - 7 + + 0 1 - - + -1,-1 + wxZRColaCharGrid; zrcolachrgrid.h 0 - + wxSTATIC_BORDER - + OnResultCellDClick @@ -2653,7 +2683,7 @@ OnResultSelectCell - + OnResultsKeyDown @@ -2691,7 +2721,7 @@ 5 - wxALL + wxALL|wxEXPAND 0 1 @@ -2719,8 +2749,8 @@ 0 wxALIGN_CENTRE - 16 - 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35 + 0 + 1 0 @@ -2737,7 +2767,7 @@ 1 ,90,90,-1,70,0 - 1 + 0 0 0 wxID_ANY @@ -2748,10 +2778,10 @@ 0 0 - + -1,-1 0 - + -1,-1 1 m_gridRecent 1 @@ -2765,22 +2795,22 @@ 0 wxALIGN_CENTRE - 35 - 1 + + 0 1 - - + -1,35 + wxZRColaCharGrid; zrcolachrgrid.h 0 - + wxSTATIC_BORDER - + OnRecentCellDClick @@ -2810,7 +2840,7 @@ OnRecentSelectCell - + OnRecentKeyDown @@ -2848,7 +2878,7 @@ 5 wxALL|wxEXPAND - 0 + 70 wxID_ANY Preview @@ -2984,7 +3014,7 @@ 0 - 4 + 0 @@ -3003,10 +3033,10 @@ 0 - wxString - wxFILTER_INCLUDE_CHAR_LIST - wxTextValidator - m_unicodeValid + + wxFILTER_NONE + wxDefaultValidator + @@ -3044,7 +3074,7 @@ 5 - wxALIGN_CENTER|wxALL + wxALL|wxEXPAND 0 1 @@ -3058,11 +3088,11 @@ 0 0 - + wxSYS_COLOUR_WINDOW 1 - 00 ZRCola,90,90,180,70,0 + 00 ZRCola,90,90,120,70,0 wxALIGN_CENTRE wxALIGN_CENTRE @@ -3073,7 +3103,7 @@ wxALIGN_CENTRE 1 - 210 + 200 1 0 @@ -3090,7 +3120,7 @@ 1 - 1 + 0 0 0 wxID_ANY @@ -3127,7 +3157,7 @@ - + wxSTATIC_BORDER @@ -3281,7 +3311,7 @@ 5 wxALL|wxEXPAND - 1 + 30 wxID_ANY Re&lated @@ -3292,8 +3322,8 @@ 5 - wxALIGN_CENTER|wxALL - 0 + wxALL|wxEXPAND + 1 1 1 @@ -3311,17 +3341,17 @@ 1 00 ZRCola,90,90,20,70,0 - wxALIGN_LEFT + wxALIGN_CENTRE - wxALIGN_TOP + wxALIGN_CENTRE 0 1 wxALIGN_CENTRE 0 wxALIGN_CENTRE - 6 - 35,35,35,35,35,35 + 0 + 1 0 @@ -3338,7 +3368,7 @@ 1 - 1 + 0 0 0 wxID_ANY @@ -3366,16 +3396,16 @@ 0 wxALIGN_CENTRE - 35,35,35 - 3 + + 0 1 - - + -1,-1 + wxZRColaCharGrid; zrcolachrgrid.h 0 - + wxSTATIC_BORDER @@ -3470,12 +3500,21 @@ - + OnOKButtonClick + + 0 + wxID_TIMER_SEARCH + m_timerSearch + 1 + 1000 + protected + OnSearchTimer + diff --git a/ZRCola/ZRCola.rc b/ZRCola/ZRCola.rc index de664ee..927e82a 100644 Binary files a/ZRCola/ZRCola.rc and b/ZRCola/ZRCola.rc differ diff --git a/ZRCola/ZRCola.vcxproj b/ZRCola/ZRCola.vcxproj index efdfaa2..6b5abd5 100644 --- a/ZRCola/ZRCola.vcxproj +++ b/ZRCola/ZRCola.vcxproj @@ -112,6 +112,7 @@ + diff --git a/ZRCola/ZRCola.vcxproj.filters b/ZRCola/ZRCola.vcxproj.filters index 1fe9219..f328a27 100644 --- a/ZRCola/ZRCola.vcxproj.filters +++ b/ZRCola/ZRCola.vcxproj.filters @@ -101,6 +101,9 @@ Resource Files + + Resource Files + diff --git a/ZRCola/locale/sl_SI.po b/ZRCola/locale/sl_SI.po index e321344..a642b3a 100644 --- a/ZRCola/locale/sl_SI.po +++ b/ZRCola/locale/sl_SI.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: ZRCola\n" -"POT-Creation-Date: 2016-05-11 14:39+0200\n" -"PO-Revision-Date: 2016-05-11 14:39+0200\n" +"POT-Creation-Date: 2016-05-13 03:37+0200\n" +"PO-Revision-Date: 2016-05-13 03:37+0200\n" "Last-Translator: Simon Rozman \n" "Language-Team: Amebis, d. o. o., Kamnik \n" "Language: sl_SI\n" @@ -17,7 +17,7 @@ msgstr "" "X-Poedit-KeywordsList: _\n" "X-Poedit-SearchPath-0: .\n" -#: zrcolafrm.cpp:93 zrcolagui.h:95 MSIBuild/En.Win32.Release.Feature-2.idtx:4 +#: zrcolafrm.cpp:93 zrcolagui.h:96 MSIBuild/En.Win32.Release.Feature-2.idtx:4 #: MSIBuild/En.Win32.Release.Shortcut-2.idtx:4 #: MSIBuild/En.x64.Release.Feature-2.idtx:4 #: MSIBuild/En.x64.Release.Shortcut-2.idtx:4 @@ -53,7 +53,7 @@ msgstr "" msgid "Start ZRCola automatically on logon" msgstr "Samodejno zaženi ZRColo ob prijavi" -#: zrcolafrm.cpp:459 +#: zrcolafrm.cpp:462 #, c-format msgid "" "ZRCola v%s\n" @@ -62,7 +62,7 @@ msgstr "" "ZRCola v%s\n" "Vse pravice pridržane 2015-%s Amebis" -#: zrcolafrm.cpp:459 +#: zrcolafrm.cpp:462 msgid "About ZRCola" msgstr "O ZRColi" @@ -95,166 +95,170 @@ msgid "Select all text" msgstr "Izberi celotno besedilo" #: zrcolagui.cpp:84 -msgid "&Insert Character..." -msgstr "Vstav&i znak ..." +msgid "C&haracter Selector..." +msgstr "Izbirnik &znaka ..." -#: zrcolagui.cpp:84 +#: zrcolagui.cpp:84 zrcolagui.cpp:170 msgid "Display character selector to select character to insert into text" msgstr "Prikaži izbirnik znaka za izbor znaka za vstavljanje v besedilo" -#: zrcolagui.cpp:90 +#: zrcolagui.cpp:95 msgid "&Send Composed" msgstr "Pošlji &sestavljeno" -#: zrcolagui.cpp:90 zrcolagui.cpp:165 +#: zrcolagui.cpp:95 zrcolagui.cpp:172 msgid "Send composed text to source window" msgstr "Pošlji sestavljeno besedilo izvornemu oknu" -#: zrcolagui.cpp:99 +#: zrcolagui.cpp:104 msgid "Send &Decomposed" msgstr "Pošlji &razstavljeno" -#: zrcolagui.cpp:99 zrcolagui.cpp:167 +#: zrcolagui.cpp:104 zrcolagui.cpp:174 msgid "Send decomposed text to source window" msgstr "Pošlji razstavljeno besedilo izvornemu oknu" -#: zrcolagui.cpp:108 +#: zrcolagui.cpp:113 msgid "Abort (De)composition" msgstr "Prekini raz/sestavljanje" -#: zrcolagui.cpp:108 +#: zrcolagui.cpp:113 msgid "Abort composition and return focus to source window" msgstr "Prekini sestavljanje in vrni fokus nazaj izvornemu oknu" -#: zrcolagui.cpp:117 +#: zrcolagui.cpp:122 msgid "&Language" msgstr "&Jezik" -#: zrcolagui.cpp:119 +#: zrcolagui.cpp:124 msgid "&Automatic" msgstr "S&amodejno" -#: zrcolagui.cpp:119 +#: zrcolagui.cpp:124 msgid "Set language according to keyboard layout automatically" msgstr "Samodejno nastavi jezik glede na izbrano tipkovnico" -#: zrcolagui.cpp:126 +#: zrcolagui.cpp:131 msgid "&Edit" msgstr "Ur&edi" -#: zrcolagui.cpp:130 +#: zrcolagui.cpp:135 msgid "&Edit Toolbar" msgstr "Orodna vrstica za ur&ejanje" -#: zrcolagui.cpp:130 +#: zrcolagui.cpp:135 msgid "Toggle edit toolbar" msgstr "Prikaži/skrij orodno vrstico za urejanje" -#: zrcolagui.cpp:134 +#: zrcolagui.cpp:139 msgid "&Compose Toolbar" msgstr "Orodna vrsti&ca za sestavljanje" -#: zrcolagui.cpp:134 +#: zrcolagui.cpp:139 msgid "Toggle compose toolbar" msgstr "Prikaži/skrij orodno vrstico za sestavljanje" -#: zrcolagui.cpp:140 +#: zrcolagui.cpp:145 msgid "Character Catalo&g" msgstr "Katalo&g znakov" -#: zrcolagui.cpp:140 +#: zrcolagui.cpp:145 msgid "Toggle character catalog panel" msgstr "Prikaži/skrij katalog znakov" -#: zrcolagui.cpp:143 +#: zrcolagui.cpp:148 msgid "&View" msgstr "Po&gled" -#: zrcolagui.cpp:150 +#: zrcolagui.cpp:155 msgid "&Help" msgstr "Po&moč" -#: zrcolagui.cpp:155 +#: zrcolagui.cpp:160 msgid "Cut" msgstr "Izreži" -#: zrcolagui.cpp:155 +#: zrcolagui.cpp:160 msgid "Cut selection" msgstr "Izreži izbor" -#: zrcolagui.cpp:157 +#: zrcolagui.cpp:162 msgid "Copy" msgstr "Kopiraj" -#: zrcolagui.cpp:157 +#: zrcolagui.cpp:162 msgid "Copy selection" msgstr "Kopiraj izbor" -#: zrcolagui.cpp:159 +#: zrcolagui.cpp:164 msgid "Paste" msgstr "Prilepi" -#: zrcolagui.cpp:159 +#: zrcolagui.cpp:164 msgid "Paste selection" msgstr "Prilepi izbor" -#: zrcolagui.cpp:162 +#: zrcolagui.cpp:167 msgid "Edit" msgstr "Urejanje" -#: zrcolagui.cpp:165 +#: zrcolagui.cpp:170 zrcolagui.h:227 +msgid "Character Selector" +msgstr "Izbirnik znaka" + +#: zrcolagui.cpp:172 msgid "Send Composed" msgstr "Pošlji sestavljeno" -#: zrcolagui.cpp:167 +#: zrcolagui.cpp:174 msgid "Send Decomposed" msgstr "Pošlji razstavljeno" -#: zrcolagui.cpp:176 +#: zrcolagui.cpp:183 msgid "Compose" msgstr "Sestavljanje" -#: zrcolagui.cpp:180 +#: zrcolagui.cpp:187 msgid "Character Catalog" msgstr "Katalog znakov" -#: zrcolagui.cpp:184 +#: zrcolagui.cpp:191 msgid "(De)Composer" msgstr "Raz/Sestavljalnik" -#: zrcolagui.cpp:223 +#: zrcolagui.cpp:230 msgid "Decomposed Text" msgstr "Razstavljeno besedilo" -#: zrcolagui.cpp:243 +#: zrcolagui.cpp:250 msgid "Decomposed Unicode Dump" msgstr "Unicode razstavljenega" -#: zrcolagui.cpp:270 +#: zrcolagui.cpp:277 msgid "Composed Text" msgstr "Sestavljeno besedilo" -#: zrcolagui.cpp:290 +#: zrcolagui.cpp:297 msgid "Composed Unicode Dump" msgstr "Unicode sestavljenega" -#: zrcolagui.cpp:407 +#: zrcolagui.cpp:417 msgid "&Browse" msgstr "Pre&brskaj" -#: zrcolagui.cpp:478 +#: zrcolagui.cpp:465 msgid "Re¢ly Used" msgstr "Nedavno &uporabljeni" -#: zrcolagui.cpp:536 +#: zrcolagui.cpp:506 msgid "Preview" msgstr "Predogled" -#: zrcolagui.cpp:541 +#: zrcolagui.cpp:511 msgid "U+" msgstr "U+" -#: zrcolagui.cpp:590 +#: zrcolagui.cpp:559 msgid "Re&lated" msgstr "&Sorodni" @@ -266,10 +270,6 @@ msgstr "" "Pritisnjena tipka INS. Zdaj vtpikajte kodo Unicode želenega znaka (do štiri " "šestnajstiške števke: 0-9, A-F), nato izpustite INS." -#: zrcolagui.h:205 -msgid "Character Selector" -msgstr "Izbirnik znaka" - # Windows charset for this language (decimal) #: MSIBuild/En.Win32.Release.Feature-2.idtx:3 #: MSIBuild/En.Win32.Release.Shortcut-2.idtx:3 @@ -285,6 +285,9 @@ msgstr "1250" msgid "Input system for linguistic use" msgstr "Vnašalni sistem za jezikoslovno rabo" +#~ msgid "&Insert Character..." +#~ msgstr "Vstav&i znak ..." + #~ msgid "&Unicode" #~ msgstr "&Unicode" diff --git a/ZRCola/res/char_select.ico b/ZRCola/res/char_select.ico new file mode 100644 index 0000000..1195ad8 Binary files /dev/null and b/ZRCola/res/char_select.ico differ diff --git a/ZRCola/res/char_select.pdf b/ZRCola/res/char_select.pdf new file mode 100644 index 0000000..748fb26 --- /dev/null +++ b/ZRCola/res/char_select.pdf @@ -0,0 +1,1794 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[5 0 R 6 0 R 39 0 R 38 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + Print + + + + + 2016-05-13T03:23:25+02:00 + 2016-05-13T03:23:25+02:00 + 2016-05-13T03:23+02:00 + Adobe Illustrator CS5 + + + + 256 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq8 888/n5+V3kxpINT1hLnUYyQ2m2AFzcBh1Vwp4Rn2kZcVeS3/APzlN+YfmN2h/L3yW5gJ4pqN/wA5 V3OxIQwwxn5ytkTIDmkBJ7iP/nJ/zGWbVPNiaJCwoILNlhdQewNogP0mWuVnMGXAUHL+ROvaiS+u +eNR1B23fl6jbkfzSzSV6+GR8fyTwKY/5xk8qUFdVvye5HogV/4DB45Xgd/0LT5fiYPaa3fwSivx /uyd/DiEOPjleBXi/Kf8zNIIfy7+YmoQ03ELyXESbD9rhNIrfSmEZ/JHAmFv50/5yq8rULy2Xmm0 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 pADSysAOTNT5AbCgGYzeyPFXYq7FX//Z + + + + + + uuid:6daf7762-f959-43d2-8b1f-10a83e54a99c + xmp.did:8E88BC3BA918E611B88DE645C8714603 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + uuid:4e2473ae-070e-461c-b5bb-4645bb364f27 + xmp.did:28F6B5FE44FAE5119915E2DE099E2805 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:27F6B5FE44FAE5119915E2DE099E2805 + 2016-04-04T11:09:54+02:00 + Adobe Illustrator CS5 + / + + + saved + xmp.iid:28F6B5FE44FAE5119915E2DE099E2805 + 2016-04-04T11:11:04+02:00 + Adobe Illustrator CS5 + / + + + saved + xmp.iid:8E88BC3BA918E611B88DE645C8714603 + 2016-05-13T03:23:01+02:00 + Adobe Illustrator CS5 + / + + + + + + Print + + + False + True + 1 + + 99.998375 + 99.998375 + Millimeters + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 35 + 31 + 32 + + + CMYK Red + RGB + PROCESS + 237 + 28 + 36 + + + CMYK Yellow + RGB + PROCESS + 255 + 242 + 0 + + + CMYK Green + RGB + PROCESS + 0 + 166 + 81 + + + CMYK Cyan + RGB + PROCESS + 0 + 174 + 239 + + + CMYK Blue + RGB + PROCESS + 46 + 49 + 146 + + + CMYK Magenta + RGB + PROCESS + 236 + 0 + 140 + + + C=15 M=100 Y=90 K=10 + RGB + PROCESS + 190 + 30 + 45 + + + C=0 M=90 Y=85 K=0 + RGB + PROCESS + 239 + 65 + 54 + + + C=0 M=80 Y=95 K=0 + RGB + PROCESS + 241 + 90 + 41 + + + C=0 M=50 Y=100 K=0 + RGB + PROCESS + 247 + 148 + 30 + + + C=0 M=35 Y=85 K=0 + RGB + PROCESS + 251 + 176 + 64 + + + C=5 M=0 Y=90 K=0 + RGB + PROCESS + 249 + 237 + 50 + + + C=20 M=0 Y=100 K=0 + RGB + PROCESS + 215 + 223 + 35 + + + C=50 M=0 Y=100 K=0 + RGB + PROCESS + 141 + 198 + 63 + + + C=75 M=0 Y=100 K=0 + RGB + PROCESS + 57 + 181 + 74 + + + C=85 M=10 Y=100 K=10 + RGB + PROCESS + 0 + 148 + 68 + + + C=90 M=30 Y=95 K=30 + RGB + PROCESS + 0 + 104 + 56 + + + C=75 M=0 Y=75 K=0 + RGB + PROCESS + 43 + 182 + 115 + + + C=80 M=10 Y=45 K=0 + RGB + PROCESS + 0 + 167 + 157 + + + C=70 M=15 Y=0 K=0 + RGB + PROCESS + 39 + 170 + 225 + + + C=85 M=50 Y=0 K=0 + RGB + PROCESS + 28 + 117 + 188 + + + C=100 M=95 Y=5 K=0 + RGB + PROCESS + 43 + 57 + 144 + + + C=100 M=100 Y=25 K=25 + RGB + PROCESS + 38 + 34 + 98 + + + C=75 M=100 Y=0 K=0 + RGB + PROCESS + 102 + 45 + 145 + + + C=50 M=100 Y=0 K=0 + RGB + PROCESS + 146 + 39 + 143 + + + C=35 M=100 Y=35 K=10 + RGB + PROCESS + 158 + 31 + 99 + + + C=10 M=100 Y=50 K=0 + RGB + PROCESS + 218 + 28 + 92 + + + C=0 M=95 Y=20 K=0 + RGB + PROCESS + 238 + 42 + 123 + + + C=25 M=25 Y=40 K=0 + RGB + PROCESS + 194 + 181 + 155 + + + C=40 M=45 Y=50 K=5 + RGB + PROCESS + 155 + 133 + 121 + + + C=50 M=50 Y=60 K=25 + RGB + PROCESS + 114 + 102 + 88 + + + C=55 M=60 Y=65 K=40 + RGB + PROCESS + 89 + 74 + 66 + + + C=25 M=40 Y=65 K=0 + RGB + PROCESS + 196 + 154 + 108 + + + C=30 M=50 Y=75 K=10 + RGB + PROCESS + 169 + 124 + 80 + + + C=35 M=60 Y=80 K=25 + RGB + PROCESS + 139 + 94 + 60 + + + C=40 M=65 Y=90 K=35 + RGB + PROCESS + 117 + 76 + 41 + + + C=40 M=70 Y=100 K=50 + RGB + PROCESS + 96 + 57 + 19 + + + C=50 M=70 Y=80 K=70 + RGB + PROCESS + 60 + 36 + 21 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + RGB + PROCESS + 35 + 31 + 32 + + + C=0 M=0 Y=0 K=90 + RGB + PROCESS + 65 + 64 + 66 + + + C=0 M=0 Y=0 K=80 + RGB + PROCESS + 88 + 89 + 91 + + + C=0 M=0 Y=0 K=70 + RGB + PROCESS + 109 + 110 + 113 + + + C=0 M=0 Y=0 K=60 + RGB + PROCESS + 128 + 130 + 133 + + + C=0 M=0 Y=0 K=50 + RGB + PROCESS + 147 + 149 + 152 + + + C=0 M=0 Y=0 K=40 + RGB + PROCESS + 167 + 169 + 172 + + + C=0 M=0 Y=0 K=30 + RGB + PROCESS + 188 + 190 + 192 + + + C=0 M=0 Y=0 K=20 + RGB + PROCESS + 209 + 211 + 212 + + + C=0 M=0 Y=0 K=10 + RGB + PROCESS + 230 + 231 + 232 + + + C=0 M=0 Y=0 K=5 + RGB + PROCESS + 241 + 242 + 242 + + + + + + Brights + 1 + + + + C=0 M=100 Y=100 K=0 + RGB + PROCESS + 237 + 28 + 36 + + + C=0 M=75 Y=100 K=0 + RGB + PROCESS + 242 + 101 + 34 + + + C=0 M=10 Y=95 K=0 + RGB + PROCESS + 255 + 222 + 23 + + + C=85 M=10 Y=100 K=0 + RGB + PROCESS + 0 + 161 + 75 + + + C=100 M=90 Y=0 K=0 + RGB + PROCESS + 33 + 64 + 154 + + + C=60 M=90 Y=0 K=0 + RGB + PROCESS + 127 + 63 + 152 + + + + + + + + + Adobe PDF library 9.90 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 3 0 obj <> endobj 8 0 obj <>/Resources<>/Properties<>/XObject<>>>/Thumb 47 0 R/TrimBox[0.0 0.0 283.46 283.46]/Type/Page>> endobj 41 0 obj <>stream +HUn1 +Fowm +.[P˂5 BBW'v|[-on,59mr/&%@9$Y;r^EQ +kHG\#TdJE| .ib&$D.{Ik/+qzFN&t%bb i!Hd*J8ށE'vɫX +t-pqIpZ!I\DuM|?Am]>jyb(/z%E* bT0SJvnbF8pVl-KqĪ~z~?R_]9{S 7I|{ F:gKagW5 +|DK1;) %c\NJ{ډ5OfWZs,~ksځf4Lwr$&^-OF2LEUpwh{ք\ߔd}Yo|Ÿ nV SsS9:Ѷk4y]a$_W+cQ۹Y}ԢSG?Tj3nu}|ҾMܾMڃrE-|`e辍;?(ZGG[ +endstream endobj 42 0 obj <> endobj 47 0 obj <>stream +8;Y!B_%D>C$q9C\Mr@'JhP:]Y*\#*P2Yj!Y&m4n6aZ*trq=B0-kMO0_0`h!#Es,A9 +=GmAaS%/@*h-p_R2Itbu,3:>K@h;ikL&,HeQ(2lqUQF5#:"GScE.[F2Krofh%`hBJAODbS1`IA8'h]oG0Qc +*\>o4>[l&@Q)\WhdF&UX\QMUsL)KcK3WV9/V">"CL4EF(6p65Q!Tjd[97-pDLu$m4~> +endstream endobj 48 0 obj [/Indexed/DeviceRGB 255 49 0 R] endobj 49 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> +endstream endobj 46 0 obj <>>>/Subtype/Form>>stream +0.153 0.667 0.882 rg +/GS0 gs +q 1 0 0 1 184.252 170.0742 cm +0 0 m +0 -39.139 -31.729 -70.866 -70.866 -70.866 c +-110.005 -70.866 -141.732 -39.139 -141.732 0 c +-141.732 39.138 -110.005 70.866 -70.866 70.866 c +-31.729 70.866 0 39.138 0 0 c +f* +Q + +endstream endobj 50 0 obj <> endobj 44 0 obj <> endobj 39 0 obj <> endobj 38 0 obj <> endobj 53 0 obj [/View/Design] endobj 54 0 obj <>>> endobj 51 0 obj [/View/Design] endobj 52 0 obj <>>> endobj 45 0 obj <> endobj 43 0 obj <> endobj 55 0 obj <> endobj 56 0 obj <>stream +%!PS-Adobe-3.0 +%%Creator: Adobe Illustrator(R) 15.0 +%%AI8_CreatorVersion: 15.0.0 +%%For: (Simon Rozman) () +%%Title: (char_select.pdf) +%%CreationDate: 5/13/2016 3:23 AM +%%Canvassize: 16383 +%%BoundingBox: 25 -264 264 -25 +%%HiResBoundingBox: 25.5122 -263.2246 263.2246 -25.5122 +%%DocumentProcessColors: Cyan Magenta Yellow Black +%AI5_FileFormat 11.0 +%AI12_BuildNumber: 399 +%AI3_ColorUsage: Color +%AI7_ImageSettings: 0 +%%RGBProcessColor: 0 0 0 ([Registration]) +%AI3_Cropmarks: 0 -283.46 283.46 0 +%AI3_TemplateBox: 142.5 -142.5 142.5 -142.5 +%AI3_TileBox: -141.4702 -548.1699 424.9297 264.71 +%AI3_DocumentPreview: None +%AI5_ArtSize: 14400 14400 +%AI5_RulerUnits: 1 +%AI9_ColorModel: 1 +%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 +%AI5_TargetResolution: 800 +%AI5_NumLayers: 2 +%AI9_OpenToView: -151 25.6665 3 1798 1031 18 1 0 73 116 0 1 0 1 1 1 1 1 0 1 +%AI5_OpenViewLayers: 27 +%%PageOrigin:-164 -538 +%AI7_GridSettings: 28.3465 10 28.3465 10 1 0 0.8 0.8 0.8 0.9 0.9 0.9 +%AI9_Flatten: 1 +%AI12_CMSettings: 00.MS +%%EndComments + +endstream endobj 57 0 obj <>stream +%%BoundingBox: 25 -264 264 -25 +%%HiResBoundingBox: 25.5122 -263.2246 263.2246 -25.5122 +%AI7_Thumbnail: 128 128 8 +%%BeginData: 20545 Hex Bytes +%0000330000660000990000CC0033000033330033660033990033CC0033FF +%0066000066330066660066990066CC0066FF009900009933009966009999 +%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 +%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 +%3333663333993333CC3333FF3366003366333366663366993366CC3366FF +%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 +%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 +%6600666600996600CC6600FF6633006633336633666633996633CC6633FF +%6666006666336666666666996666CC6666FF669900669933669966669999 +%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 +%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF +%9933009933339933669933999933CC9933FF996600996633996666996699 +%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 +%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF +%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 +%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 +%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF +%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC +%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 +%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 +%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 +%000011111111220000002200000022222222440000004400000044444444 +%550000005500000055555555770000007700000077777777880000008800 +%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB +%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF +%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF +%524C45FD25FFA8A87D522727FD09F827287D7DA8FD69FF7D52FD07F82727 +%51272727512727FD06F8277D7DFD62FF7D52F8F8F8272752767D7DFD04A7 +%A8A7A8A7A8A7A77D7D525227FD04F852A8FD5CFFA852F8F8F827517D7DA7 +%A1A7A1A77DA77DA77DA77DA77DA77DA77DA7A7A77C7C27FD04F87DA8FD57 +%FFA827F8F82752A7A7CAA7A7A1A8A1A7A1A8A1A7A1A8A1A7A1A8A1A7A1A8 +%A1A7A1A8A7A8A17D51F8F8F852FD54FF7D27F8F8277C7DA8A1A77DA77DA7 +%7DA77DA77DA77DA77DA77DA77DA77DA77DA77DA77DA77DA7A1A87D52F8F8 +%F852A8FD50FF27F8F8517CA8A7A77DA7A1A77DA7A1A77DA7A1A77DA7A1A7 +%7DA7A1A77DA7A1A77DA7A1A77DA7A1A77DA8A7A75227F8F87DFD4DFF7DF8 +%F8267DA1A77DA77DA77DA77DA77DA77DA77DA77DA77DA77DA77DA77DA77D +%A77DA77DA77DA77DA77DA77DA77DA77D7CF8F8F8A8FD49FFA852F82752A8 +%A7A7A1A8A1A7A1A8A1A7A1A8A1A7A1A8A1A7A1A8A1A7A1A8A1A7A1A8A1A7 +%A1A8A1A7A1A8A1A7A1A8A1A7A1A8A7A751F8F87DFD47FF7DF8F8517DA77D +%A77DA77DA77DA77DA77DA77DA77DA77DA7A1A7A1A8A7A7A1A8A1A77DA77D +%A77DA77DA77DA77DA77DA77DA77DA7A1A77C27F827A8FD44FF52F8F87CA7 +%A8A1A77DA7A1A77DA7A1A77DA7A1A7A1A8A7A77DA77C7C527C5252527D7C +%A77DA8A7A7A1A7A1A77DA7A1A77DA7A1A77DA7A1A8A152F8F8A8FD42FF27 +%F8F87DA7A77DA77DA77DA77DA77DA77DA77DA77D7D5251FD0EF8265252A1 +%7DA77DA77DA77DA77DA77DA77DA77DA7A17CF8F87DFD40FF27F827A8A7A7 +%A1A8A1A7A1A8A1A7A1A8A7A8A7A75227F8F8F8272752525959847D7E5959 +%525205FD04F85152A7A7A8A7A7A1A8A1A7A1A8A1A7A1A8A77DF8F87DFD3E +%FF27F827A77DA77DA77DA77DA77DA77DA7A1A75227F8F8F828528484A985 +%AFA9AF85AF85AF85AF85A9847E2E27F8F8F8517CA8A1A77DA77DA77DA77D +%A77DA7A77DF8F852FD3CFF27F827A8A7A77DA7A1A77DA7A1A77DA8A77CF8 +%F8F82859A9A9AF85AF85AF84AF85AF84AF85AF84AFA9AFA9AFA9845227F8 +%F827A1A7A77DA7A1A77DA7A1A77DA7A7A7F8F852FD3AFF27F827A77DA77D +%A77DA77DA77DA7A1A75227F8F8288485AF84A984A984A984A984A984A984 +%A984A984A984A984AF85AF847D27F8F8517DA77DA77DA77DA77DA77DA7A1 +%A7F8F852FD38FF27F851A8A1A8A1A7A1A8A1A7A1A8A7A727F8F85284AFA9 +%AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AFAFAF59 +%27F8F852A8A7A7A1A8A1A7A1A8A1A7A7A7F8F87DFD36FF52F827A7A1A77D +%A77DA77DA77DA7A17DF8F80584A9AF84AF84A984AF84A984AF84A984AF84 +%A984AF84A984AF84A984AF84A984AF85AF8559F8F827A7A7A77DA77DA77D +%A77DA7A1A1F8F8A8FD34FF7DF826A7A1A7A1A77DA7A1A77DA8A752F8F852 +%AFA9AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84 +%AF85AF84AF85AFA9A927F8F87DA7A77DA7A1A77DA7A1A7A77DF827FD33FF +%A8F8F87DA1A77DA77DA77DA77DA77D51F8F859AF84A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A985AF +%52F8F87CA7A77DA77DA77DA77DA7A152F852FD32FF52F87DA7A7A1A8A1A7 +%A1A8A1A8A14BF82884AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AFA9AF5900F852A7A8A1A7 +%A1A8A1A7A1A8A751F8A8FD30FF7DF851A1A77DA77DA77DA77DA77D27F82E +%85AF84AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A9 +%84AF84A984AF84A984AF84A984AF84AF7EF8F852A1A77DA77DA77DA77DA7 +%7DF8F8FD30FFF827A1A77DA7A1A77DA7A1A7A127F82E85AF85AF84AF85AF +%84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF +%85AF84AF85AF84AF85AF7E27F876A7A7A1A77DA7A1A77DA876F827FD2EFF +%27F852A77DA77DA77DA77DA7A127F82E85A984A984A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984AF7EF8F87CA1A77DA77DA77DA77DA727F87DFD2CFFA8F827A8 +%A7A7A1A8A1A7A1A8A752F82EA9AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF7EF8F8A7A7A7A1A8A1A7A1A8A7A7F827FD2CFF27F87DA1A77DA7 +%7DA77DA7A17DF80084AF84A984AF84A984AF84A984AF84A984AF84A984AF +%84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A9 +%84AF59F8F8A7A1A77DA77DA77DA7A752F87DFD2AFFA8F852A7A77DA7A1A7 +%7DA7A7A7F8F87EAF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF +%85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF +%85AF52F827A8A1A77DA7A1A77DA87DF8F8FD2AFF27F87CA77DA77DA77DA7 +%7DA727F82EAF84A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84AF00F852A77DA77DA77DA77DA727F87DFD28FFA8F827A8A7A7A1A8A1A7 +%A1A87CF827AFA9AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AFAF84F827A7A7A1A8A1A7A1A8A7A7F827FD28FF52F87CA1A77DA77DA7 +%7DA77D27F87E85AF84A984AF84A984AF84A984AF84A984AF84A984AF84A9 +%84AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF +%84A984AFA952F852A7A77DA77DA77DA7A751F8A8FD27FFF827A7A77DA7A1 +%A77DA7A77CF852AFAF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84 +%AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85 +%AF84AF85AF84AF8405F8A7A7A77DA7A1A77DA87CF852FD26FF7DF851A77D +%A77DA77DA77DA7F8F87EAF84A984A984A984A984A984A984A984A984A984 +%A984A984A984A984A984A984A984A984A984A984A984A984A984A984A984 +%A984A984A984A984A984AF52F851A77DA77DA77DA77DA7F8F8A8FD25FF52 +%F8A7A7A7A1A8A1A7A1A876F82EAF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AFA9AFF827A1A7A1A8A1A7A1A8A752F8A8 +%FD25FFF827A1A77DA77DA77DA7A127F88485AF84A984AF84A984AF84A984 +%AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84 +%A984AF84A984AF84A984AF84A984AF84A984AFA952F87CA7A77DA77DA77D +%A77CF827FD24FF7DF852A87DA7A1A77DA7A77DF82EA9AF84AF85AF84AF85 +%AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84 +%AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF84F827A8A1 +%A77DA7A1A7A1A82627FD24FF52F87DA1A77DA77DA77DA751F853AF84A984 +%A984A984A984A984A984A984A984A984A984A984A984A984A984A984A984 +%A984A984A984A984A984A984A984A984A984A984A984A984A984A984A984 +%AF27F87CA77DA77DA77DA7A152F8A8FD23FF2727A1A7A1A8A1A7A1A8A727 +%F8AFA9AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AFAF7DF87CA7A7A1A8A1A7A1A87CF852FD22FFA8F827A77DA7 +%7DA77DA77DA1F82785AF84A984AF84A984AF84A984AF84A984AF84A984AF +%84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A9 +%84AF84A984AF84A984AF84A984AF84F826A77DA77DA77DA77DA1F852FD22 +%FFA8F852A7A7A1A77DA7A1A852F853AF84AF85AF84AF85AF84AF85AF84AF +%85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF +%84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF85AF27F87DA8A1A77DA7 +%A1A7A127F8FD22FF52F852A77DA77DA77DA7A151F88485A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A98552 +%F87C7DA77DA77DA77DA727F8A8FD21FF52F8A1A7A8A1A7A1A8A7A7262785 +%AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF59F852CAA1A7A1A8A1A7A752F8A8FD21FF27F87DA77DA7 +%7DA77DA77DF805AF85A984AF84A984AF84A984AF84A984AF84A984AF84A9 +%84AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF +%84A984AF84A984AF84A984AF84A98584F851A1A77DA77DA77DA752F87DFD +%21FF27F8A7A7A77DA7A1A7A1A7F852A9AF85AF84AF85AF84AF85AF84AF85 +%AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84 +%AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF840527A7A1A7A1 +%A77DA7A77DF87DFD21FFF8277DA77DA77DA77DA752F82EAF84A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A9F8277DA77DA77DA77DA77CF852FD21FFF827A8A7A7A1A8A1A7A77DF8 +%59AFAF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF8528F8A7A1A8A1A7A1A8A7A7F852FD21FFF84BA1A7 +%7DA77DA77DA751F859AF84AF84A984AF84A984AF84A984AF84A984AF84A9 +%84AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF +%84A984AF84A984AF84A984AF84A984AF84AF27F87DA77DA77DA77DA77DF8 +%27FD21FFF827A87DA7A1A77DA7A776F87EA9AF84AF85AF84AF85AF84AF85 +%AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84 +%AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AFAF52F8A7A7 +%A77DA7A1A7A1A7F852FD21FFF851A1A77DA77DA77DA751F859AF84A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984AF27F87CA77DA77DA77DA77CF827FD21FFF827A8A1A8A1A7A1A8A7 +%76F87EAFAF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF85AFAF52F8A7A7A7A1A8A1A7A1A7F852FD21FFF851 +%A1A77DA77DA77DA852F853AF84A984AF84A984AF84A984AF84A984AF84A9 +%84AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF +%84A984AF84A984AF84A984AF84A984AF84A984AF27F87DA77DA77DA77DA7 +%7DF852FD21FFF827A8A1A77DA7A1A7A77DF859A9AF85AF84AF85AF84AF85 +%AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84 +%AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF8527F8 +%A7A1A7A1A77DA7A7A1F852FD21FFF8277DA77DA77DA77DA776F82EAF84A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A9F8277DA77DA77DA77DA77CF852FD21FF27F8A7A7A7A1A8A1 +%A7A1A7F852A9AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF85AF85AF84F827A8A1A8A1A7A1A8A77DF87DFD21FF +%27F87CA77DA77DA77DA77D2600A984AF84A984AF84A984AF84A984AF84A9 +%84AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF +%84A984AF84A984AF84A984AF84A984AF84A984AF857EF852A7A77DA77DA7 +%7DA852F87DFD21FF7DF87DA1A7A1A77DA7A1A727F884AF84AF85AF84AF85 +%AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84 +%AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF59 +%F852A8A1A77DA7A1A7A752F8A8FD21FF7DF852A77DA77DA77DA7A752F87E +%85A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A9852EF87D7DA77DA77DA77DA726F8A8FD21FFA8F852A7A8A1 +%A7A1A8A1A876F852AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF85AF85AF85AF0527A1A8A1A7A1A8A1A7A12727FD22 +%FFA8F826A77DA77DA77DA7A1A1F82785A984AF84A984AF84A984AF84A984 +%AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84 +%A984AF84A984AF84A984AF84A984AF84A984AF84AF7DF827A77DA77DA77D +%A7A17DF852FD23FF27F87DA77DA7A1A77DA7A74BF884A9AF84AF85AF84AF +%85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF +%84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AFAF59F87C +%A7A77DA7A1A77DA852F87DFD23FF52F87CA1A77DA77DA77DA752F82EAF84 +%A984A984A984A984A984A984A984A984A984A984A984A984A984A984A984 +%A984A984A984A984A984A984A984A984A984A984A984A984A984A984A984 +%A984AFF8F87CA77DA77DA77DA7A14BF8A8FD23FFA8F851A8A1A8A1A7A1A8 +%A7A7F827A9AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF7EF827A8A7A7A1A8A1A7A1A7F827FD25FFF8277DA77D +%A77DA77DA7A751F87EA9A984AF84A984AF84A984AF84A984AF84A984AF84 +%A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984 +%AF84A984AF84A984AF84A9852EF87DA1A77DA77DA77DA752F852FD25FF52 +%F87DA7A77DA7A1A77DA87DF827AF85AF84AF85AF84AF85AF84AF85AF84AF +%85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF +%84AF85AF84AF85AF84AF85AF84AFA984F827A7A77DA7A1A77DA7A752F8A8 +%FD25FF7DF827A77DA77DA77DA77DA727F859AF84A984A984A984A984A984 +%A984A984A984A984A984A984A984A984A984A984A984A984A984A984A984 +%A984A984A984A984A984A984A984A984A984AF27F852A77DA77DA77DA77D +%A7F827FD27FF2727A1A7A1A8A1A7A1A8A77DF827A9AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF7EF827A8A7A7A1A8A1A7 +%A1CA52F852FD27FF7DF87CA7A77DA77DA77DA7A751F859A9A984AF84A984 +%AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84 +%A984AF84A984AF84A984AF84A984AF84A984AF84A98527F87CA1A77DA77D +%A77DA7A127F8A8FD28FFF8F8A8A7A77DA7A1A77DA87DF8F8A9A9AF84AF85 +%AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84 +%AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AFAF59F852A7A77DA7A1 +%A77DA7A77DF852FD29FF52F852A77DA77DA77DA77DA752F827AF84A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A98584F8F87CA77DA77DA7 +%7DA77DA727F87DFD2AFFF827A7A7A1A8A1A7A1A8A7A827F853AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF27F852CAA1A7A1A8A1A7 +%A1A87CF827FD2BFF52F87CA7A77DA77DA77DA7A1A1F8F859AF84AF84A984 +%AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84 +%A984AF84A984AF84A984AF84A984AF85AF28F827A77DA77DA77DA77DA7A1 +%27F8A8FD2CFFF8F8A7A7A77DA7A1A77DA7A77DF8F884AF84AF85AF84AF85 +%AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84 +%AF85AF84AF85AF84AF85AF85AF52F827A8A7A77DA7A1A77DA7A77CF827FD +%2DFF52F827A77DA77DA77DA77DA7A176F8F87EAF84A984A984A984A984A9 +%84A984A984A984A984A984A984A984A984A984A984A984A984A984A984A9 +%84A984A984A984AF52F8F8A17DA77DA77DA77DA77DA7F8F8F827A8FD2CFF +%27F87CA8A1A8A1A7A1A8A1A7A77CF82784AF85AF85AF85AF85AF85AF85AF +%85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF85AF +%85AFA9AF53F8F8A1A7A7A1A7A1A8A1A7A1CA51F8282FF827AFFD2BFFA8F8 +%277DA77DA77DA77DA77DA7A152F8F87DAF84A984AF84A984AF84A984AF84 +%A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984AF84A984 +%AF52F8F87DA7A77DA77DA77DA77DA752F8F8303028F827A8FD2BFF7DF852 +%A7A77DA7A1A77DA7A1A7A77CF8F859AFA9AF84AF85AF84AF85AF84AF85AF +%84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AF85AF84AFA9AF28F8 +%F87DA7A7A1A77DA7A1A77DA87D26F82F3036302EF827A8FD2BFF27F87CA7 +%A77DA77DA77DA77DA7A17CF8F82EAF85A984A984A984A984A984A984A984 +%A984A984A984A984A984A984A984A984A984A984A984A9858405F8F8A7A1 +%A77DA77DA77DA77DA77D27F8282F302F302F28F827A8FD2AFFA827F87DA7 +%A8A1A7A1A8A1A7A1A8A7A120F82784AFAF85AF85AF85AF85AF85AF85AF85 +%AF85AF85AF85AF85AF85AF85AF85AF85AF85AFA9AFA97DF8F827A8A7A7A1 +%A8A1A7A1A8A1A7A752F828305A30362F5A302EF827FD2BFF7DF8F87DA1A7 +%7DA77DA77DA77DA7A1A727F8F85284AF85A984AF84A984AF84A984AF84A9 +%84AF84A984AF84A984AF84A984AF84A985AF7E27F8F852A77DA77DA77DA7 +%7DA77DA7A752F8052F302F302F302F303028F827A8FD2AFF7DF8F8A7A7A7 +%A1A77DA7A1A77DA7A7A87627F80552AFAFAF85AF85AF84AF85AF84AF85AF +%84AF85AF84AF85AF84AF85AF85AFAF8428F8F8517DA8A1A77DA7A1A77DA7 +%A1A7A77DF8F82F5A2F302F3630302F5A302EF827FD2BFF52F8F8A77DA77D +%A77DA77DA77DA77DA77D52F8F8F8527EAF85AF84A984A984A984A984A984 +%A984A984A984A984AFA9A9592EF8F8F87CA1A77DA77DA77DA77DA77DA7A7 +%7CF8F82F302F302F302F302F302F303028F827A8FD2AFF52F8F8A7A7A7A1 +%A8A1A7A1A8A1A7A1A8A7A75227F8F8277D84AFAFAFA9AF85AFA9AF85AFA9 +%AF85AFA9AFA9AF7E5905F8F82752A8A7A7A1A8A1A7A1A8A1A7A1A8A77DF8 +%F82F5A2F5A30362F5A30362F5A3036302EF827AFFD2AFF52F8F8A1A7A77D +%A77DA77DA77DA77DA7A1A77D7C27F8F8F80552598484A984AFA9AF85AF85 +%A98484532EFD04F8277DA1A77DA77DA77DA77DA77DA77DA7A17CF8F82836 +%2F302F302F302F302F302F302F303028F827A8FD2AFF7DF8F87DA7A77DA7 +%A1A77DA7A1A77DA7A1A7A7A87D5227FD04F805052727522E522727FD05F8 +%27277C7DA8A7A7A1A77DA7A1A77DA7A1A77DA8A752F8002F362F3630302F +%3630302F3630302F363036302EF827A8FD2AFF7DF8F852A1A77DA77DA77D +%A77DA77DA77DA77DA7A1A77C7D51512627FD07F8272751527D7DA7A1A77D +%A77DA77DA77DA77DA77DA77DA77C27F8002F362F302F302F302F302F302F +%302F302F302F302F28F827A8FD2AFFA827F8517DCAA7A7A1A8A1A7A1A8A1 +%A7A1A8A1A7A1A8A7A8A7A8A1A77DA77DA77DA7A7A8A7A8A7A7A1A8A1A7A1 +%A8A1A7A1A8A1A7A1A8A7A87C27F8282F5A30362F5A30362F5A30362F5A30 +%362F5A30362F5A302EF827FD2BFFA852F8F852A8A1A77DA77DA77DA77DA7 +%7DA77DA77DA77DA77DA7A1A77DA7A1A77DA77DA77DA77DA77DA77DA77DA7 +%7DA77DA77DA7A1A727F8F82E30302F302F302F302F302F302F302F302F30 +%2F302F302F303028F827A8FD2BFF7DF8F827A7A7A77DA7A1A77DA7A1A77D +%A7A1A77DA7A1A77DA7A1A77DA7A1A77DA7A1A77DA7A1A77DA7A1A77DA7A1 +%A77DA8A77CF8F8002F305A30302F3630302F3630302F3630302F3630302F +%3630302F5A302EF827FD2DFF27F8F8527DA77DA77DA77DA77DA77DA77DA7 +%7DA77DA77DA77DA77DA77DA77DA77DA77DA77DA77DA77DA77DA7A1A77627 +%F8F806302F302F302F302F302F302F302F302F302F302F302F302F302F30 +%2F303028F827A8FD2CFF7D27F8F851A7A7A8A1A8A1A7A1A8A1A7A1A8A1A7 +%A1A8A1A7A1A8A1A7A1A8A1A7A1A8A1A7A1A8A1A7A1CAA77D27F8F827F82F +%30362F5A30362F5A30362F5A30362F5A30362F5A30362F5A30362F5A3036 +%302EF827AFFD2DFF7DF8F8F8527CA7A1A77DA77DA77DA77DA77DA77DA77D +%A77DA77DA77DA77DA77DA77DA77DA7A7A75227F8F827A8A827F82830302F +%302F302F302F302F302F302F302F302F302F302F302F302F302F303028F8 +%27A8FD2EFF7D27F8F827527CA8A7A8A1A7A1A77DA7A1A77DA7A1A77DA7A1 +%A77DA7A1A7A1A8A7A77652F8F8F852A8FD04FF27F82E30362F3630302F36 +%30302F3630302F3630302F3630302F3630302F363036302EF827A8FD2FFF +%A827FD04F852527D7DA7A7A77DA77DA77DA77DA77DA7A1A7A1A77D7D514B +%F8F8F82752A8FD06FFA827F82830302F302F302F302F302F302F302F302F +%302F302F302F302F302F302F302F28F827A8FD31FF7D5227F8F8F8272752 +%527D7DA77DA77DA77DA77C7D52522727F8F8F82752A8FD0AFFAF27F82E30 +%5A30362F5A30362F5A30362F5A30362F5A30362F5A30362F5A30362F5A30 +%2EF827FD33FFA8A85252FD12F827527DA8FD0EFFA827F82830302F302F30 +%2F302F302F302F302F302F302F302F302F302F302F302F303028F827A8FD +%36FFA8A87D7DFD045227FD04527D7DA8A8FD13FFA827F82E305A30302F36 +%30302F3630302F3630302F3630302F3630302F3630302F5A302EF827FD5B +%FFA827F8282F302F302F302F302F302F302F302F302F302F302F302F302F +%302F302F303028F827A8FD5BFF27F82E30362F5A30362F5A30362F5A3036 +%2F5A30362F5A30362F5A30362F5A3036302EF827AFFD5AFFA827F8283030 +%2F302F302F302F302F302F302F302F302F302F302F302F302F302F303028 +%F827A8FD5BFF27F82E30362F3630302F3630302F3630302F3630302F3630 +%302F3630302F363036302EF827A8FD5AFFA827F82830302F302F302F302F +%302F302F302F302F302F302F302F302F302F302F302F28F827A8FD5AFFAF +%27F82E305A30362F5A30362F5A30362F5A30362F5A30362F5A30362F5A30 +%362F5A302EF827FD5BFFA827F82830302F302F302F302F302F302F302F30 +%2F302F302F302F302F302F302F303028F827A8FD5AFFA827F82E305A3030 +%2F3630302F3630302F3630302F3630302F3630302F3630302F5A302EF827 +%FD5BFFA827F8282F302F302F302F302F302F302F302F302F302F302F302F +%302F302F302F303028F827A8FD5BFF27F82E30362F5A30362F5A30362F5A +%30362F5A30362F5A30362F5A30362F5A3036302EF827AFFD5AFFA827F828 +%30302F302F302F302F302F302F302F302F302F302F302F302F302F302F30 +%3028F827A8FD5BFF27F82E30362F3630302F3630302F3630302F3630302F +%3630302F3630302F363036302EF827A8FD5AFFA827F82830302F302F302F +%302F302F302F302F302F302F302F302F302F302F302F302F28F827A8FD5A +%FFAF27F82E305A30362F5A30362F5A30362F5A30362F5A30362F5A30362F +%5A30362F5A302EF827FD5BFFA827F82830302F302F302F302F302F302F30 +%2F302F302F302F302F302F302F302F303028F827FD5BFFA827F82E305A30 +%302F3630302F3630302F3630302F3630302F3630302F363030302FF8F87D +%FD5CFFA827F8282F302F302F302F302F302F302F302F302F302F302F302F +%302F30302FF8F87DFD5FFF27F82E30362F5A30362F5A30362F5A30362F5A +%30362F5A30362F5A302FF8F87DFD60FFA827F82830302F302F302F302F30 +%2F302F302F302F302F302F30302FF8F87DFD63FF27F82E30362F3630302F +%3630302F3630302F3630302F36302FF8F87DFD64FFA827F82830302F302F +%302F302F302F302F302F302F302F2FF8F87DFD66FFAF27F82E305A30362F +%5A30362F5A30362F5A3036302FF8F87DFD68FFA827F82830302F302F302F +%302F302F302F30302FF8F87DFD6AFFA827F82E305A30302F3630302F3630 +%30302FF8F87DFD6CFFA827F8282F302F302F302F302F30302FF8F87DFD6F +%FF27F82E30362F5A30362F5A302FF8F87DFD70FFA827F82830302F302F30 +%302FF8F87DFD73FF27F82E30362F36302FF8F87DFD74FFA827F82830302F +%2FF8F87DFD76FFAF27F82E302FF8F87DFD78FFA827F828F8F87DFD7AFFA8 +%27F8F87DFD7CFFA8277DFD10FFFF +%%EndData + +endstream endobj 58 0 obj <>stream +H˪e7@0iA,@ 2M:T%&oz{;w?d_?~|{O~ <ľ?ķ\r|o}z{1YP&uZPJяت:_{|~!opRz=H5&ьq"F辕{yǷnNnH D7ʭ@㶰`?9s]Z@*UBq!#wRjHO㱵nbFȅ,z S }_,Զ%!APǶj;Hi *D\0ю|ªf[-ZUq׫ 4 يJZ:ƥc.#tJGj +JU"[P-mfBgAܞObVhg4 7n1}.8׫_]qb?:):!/ E3ck VQ4RB=BE- Fu! Bf=KV[UU}U|t@fNNNER]hQ=L2JjyMsxN]h9jQK{mb썒]M-A=#N 2c\;Һ*!/Iw$^J%?.:fBmY +0jS*F?axmH<ʭd]ȶAaXF9 L:Gg#-MX!+]lW䞒( +EcfB@?.Ob@쉮.;F"enCVKB]Ó@h4/+%Vb7^JIiEȺm(f?tWW^&fӳ>=\m7٣O*w5֧k[Ix_; X] ҸoqWm~xG%ݞЕ5ձ3"cgHmQ!(SnGl-9<=眣ocC '0Tyk^K_hcUWeQ*iثKV +u5*x0jnuiWRRFғD+DplmᭀNajMȻ뱢e(xs]}N :_ +لXrv*m0upoGewӸR##rӳ]wٮ6G.>9x wܓwUiq- {S>ls!G9A0'uQ& EVK5/4J{؊Fd ܁.Ŧyi=6k47Gd(s\xLyΆA ݛj"I1[t@މR}|Iii.v6ⲛMEMq-%"]_iC*=_CWZp\U~ϛkN·䉶nNٛPH$ +Gtn;}awCaViɊn׾c{B{n^ȅ^)r;3_ 8/ ·Pk\D[/'uӶ֋9=jmH"~w~́^ܥ +* ZU~hoduZ1SP@OH/t7bu^"v~֩pt]j)𜛦$i4?9@G~/_+??;\Qge\X +15$j+cB#Aw08Y.aM!q^2v;!:o!! stc`CĐWx؁e᳠>m`8Uw'hݾ_]1Gwb)R11GkBnz-|B'Ļd.NNXϋg4{(}6;ieS \H#?[̠q;TlF zCMnd"zQO=9V2X +?J9r6Xn4k9en\<| +qۉXK;h]t ݇V@WǴ +~ȴBݎޯ9 QRnf},VkDvKEٖ^^9넨`U`]y}1*Eﺭ#궼xVi swmngyod?Q1|AQ9/Yϋu"{ Eve+MC$i}y=>b%Nja6FX2Bh[! ԳdKK6^1f̋Ȇ|_W>`xuTJ-q<A6NPXG]sC+r#`mG-p ^pPpq|jcV|Vn(Ԉk[?aׯ+K???&67knz{}2@gLܬO%Hǜ<s;Ǽ#qvyM2zvч(uQIJU4˟lW-5rs ZWE}{3#a6&^ DxApq\Vu@6mQ==Q𩂭!y˳^ 9]|Q6>b5GgWW|zࢹp8s%?[Qy#J +SYgEimSNe`QyקC{=ֶO#ьYC9oW_gh V +t%; @6h`r3n}}TNG~?CnjyfVLx<_zW6wڴԷ[>:ݶ\v:\3!mA͗ 6..A1E)[Cكod>kH_q_a>7/-Myof;4CDDD +BMBI$f4si$VvB{~є"I%wp˦6ɜ/R{eJ`駣)HA|<+zânmDqmP]*W&la Y– 9CJö1/9 gy0w#3Ǽ MzxzgЛN@Ďxh\_/&@H":d f%0%)(3&RahOA??w,-~ +W 5*K5k H [ H ls|̈U|m)x  >H|l E !e HKH!h H  w2@($+Ha;62cw*-< +GɣmVR-1&'"'[τϭƧNl|b$1w rS?0c>XτϭƧIlThI|j +RFTLȇbI2rqd;Tt$'FT\^rGx +LDF׺[ORҒ3U\մ#09Зз }[ +$p^R%DB͕}FHQpUZE\hz MQ$Ol qc|BD\Nq|mQ()4U{|Ě|k'>&>n+ec[|\2A>Cf1dk@4qT mP 6?YTb"VqEcQ'>Gn#7"V"BŌG(I|L|=>ǶGc4, 1 +FdLBD2Rȝ m +% !%<x2Uc$>G5:DHw4%n}d)ޚr2/o[!K>HbPH0R"FMxLxj<ǖ +ŽጊQ.Wda$X41q([qPQ2)[&#gzǡ_Ɍ4<d]3 ڑ(@Z ԴR;r\`y߾(Mižo|sm12g:M[jl?<5BhX}l鱥ǖǃ8)Òhg$>8_KP uqӡɈFZGLґv ήV2n''C`1)iwLs%Ë_Gږ%R׾XnkOEUl I@kp +<, +J,G>`;z$ԧ񔱮,s:vn4NiQ8:OG SF`(oe) ,:=p\Uljs7Fz&YݟF| +(Mboޭ\jO߃t}9MjV!EcGT#FGA,pm_C&+5j$* 6p70hg//S"Sܪ/K.trKi=.b2ɎaHiLefK8M)oISU4|ǦCiWFp#Eajk*5#lB=<%QidhZZ>C!T,BŌ* O|Gxr> $l옠\u,g;FMj暦gNyh)5nI4Q3`VB oSH {w/Rtz|Ջa +|fA:e||{K˸cYzr 'Xr[v_y.yT\b [`yf<$-c~MC95ed$Oοxd*>Prd9G!ݯNQޑX +2d1v\"穳qi-8}+պ\0"RD6Nde'kys}=xJ&$7 M~܈l- F2F^{'Zי:bq[VZQ*2ͧ\ni'sI]qqWq|s5='s̼a@ó aX(aYLpiɸ, ԅ^$iNDJE+o]*d"KeپmCȱLh.ntym)ߐpNwd22 9evDۡ^{p;=d+|gspץX[;| +G⪌ y." +r$,lKa$p5G~ 0^S +endstream endobj 59 0 obj <>stream +HWnH}`7@%tÓM{262AXi2d*ia}"<`~h(uֹ۹^պxsoⴽ^V-w<ع'Uހ_Oꋶ^5xT\'j=NWe1Usռwinû<WP=o.bpF -,1Q( zWjg%%TQ]?ޗBE(;_=Շqs} :WuKFOop5;=rw]59^.7WlW7nFaA/VuӂEW|ᗺ :=9<=:> CN E,(mIX2u9UTft2Hh4YABT#q&t2?8[G!8NZ"ozQ.zAB>Hg ˉF7,3ɜElVQ۸ %7f.}{~,`o1C1-F$*Ёb[L`BGa[Fbڍ!QbU <-q;U#:"OakkFf2{.Q|:hteYFo%f`[CU鐕obW "#G6G}>Y6F d*F/F1bZ['sG@B9a8Wz,W 5 Cй1$15e 8[cYgX(<IJ4٣0Lo=~o>`:Lt!خvi mz"D"jFVQ9M[pd/acp zEvn~@J1vCF -f&^;1: ,zN0$^rNiCKR_1B㺬O,1"#ҡTu*h&98P +AH v)2QIlP ĄՁT(,B_4fѡRKs+u7^}lrRC@ c'I >$[Y` + +4XF؞̊j2`;J'@-QZ|(`"P nl"e=+ᜊ0*}NwyѵP;71>@x +;4X)8dtCUc5Kh )~9ۦF$6hn\Cn(: +/4=-FkÄ% &4"SR_H2h 78ǃ@THASGijWy%UbqSQ8TЍ ,8D +mS[5_ȓo f +*_ "؆\ E'N3>OaTr^?]9JtK tsYՇ,^׋G;lqڑ4=fūu,}ݭ'm֗˪8)u}Cx=P`檄%Zru-.'ԥYCƑ˶5iβ!(t@birYb7k8-}GE&Ppt@qSI +j t#pЂIސSH -*7 +` G=&N@ rTXx# #9p^|llg(#4u#Vɥd|DGk^,nNyws`Uh ܪYt|6lEG\!$MWGIF3m?zű 8@5K^2(h ]Jt$F`$A~Ptx,FҐT: 5"Z<$$;TRtw[gnwO\bnLEݼ{jfiB%=pݞy}oTͲ}c9_}զGuS +`ߪ-rT7e[umWWwsHO?_jmǢS,vri?9qz48YD\S@Rn_%Q^Φ3<\TI#nGK%HUU캌$N8DpaSdɨG>z^j jOO)C,}w+%+dSϼ;b e 5DsUY9|3wX7)$_03 k!RYUC%J{[w +S +E8.NB,` Eǃ4[((]2/o'׻/ൟ^,^OKAĈЇ+0je`r_&'f}=GwK ! 6Q_N~__ڭѤի/WN?wBכN {8o +t-Y{Aa#) W.y,^0'*KUŠm;>z Xo_BAM玃fH!qn D (d!6JQjT<5V2B 9FZ;`t?>Č ]G%vNɫ;,8;<,\ +L}c\1_G5IX1/4g\),[S۲2⪌Ìt~6HGqt LyNh+TDЯY&g'i^p2gZܼ^pR{9 +鮔>KICa~|7Y:mȽ-Z Gvc-8`vZlZF;p;ɳBo}pŽv[c&h,E{Qf؟w=(fЙʈ7J};""`A6R5MX x8:s9o}&}V3ѐ fmde0M%;Ћ<˅)Г;R3H1 0=V}B⫄?ح^`4{_if9zr1j W+au-h ZJCAFīTstoSk6>yBg̓Ѩ㻦c̊c|68h*;MţMjD (eQw?G%x/_\~SxwUqp_8++5Z0m3xr9qVTG1_)FA=dR?yG + 熰k' Q:J5s<)s{;Cy8#Im?r +-SZK[ס"A]Kl>mCglk*3bq" W-.,xa?Dʲ 9u|X%[E]m9ͥ4L0ucEɖ2؃Y*rw +r{vȅ߾j6O(hGDGSQiSPP I7pkܝ+"v7(F44zKġVUPPwħq`-@Y:&4fPHk~5d:}JUQګ^'OC59)rj!.MpM7)Ő%oYrC~OoG{y6Y6!/ajcjoN|R7#+pGhH}AzPWU*T1_D? źK8I=Z& *b޾xHQu(Z۾T{Rr jyG vBY1; ogU>ĚL]fkҌME=z:fPn0Tbqm%l,yD69ʼnR <ކM0?nކ- *^70pEU^ Ḳ4^%]Ymt)m8+uْAθpMA΅ 9tnn`%;s;m; Wʸ$3]?;љXlkehr-% 3J#2Kkt݉شKxMڢ߶"T +DtXH$J"v &̑\m2sA MhьzV3\q pH-3a "V+>sc\GH-x\##-v䝠p/7Gbe[7.7{[ץ>-܁#SS _N[-D^F|>ψfr_mH *44 +aFl}]${ΧINթ +2邯C?1j9[{Ȁ_^"[˪;.2<]^<&^auQʂւE 5?DJPsLCS[ܤTJ%cJz5Bbh>, +0g@e$5cwPnevI3l]O&y4wRG#Z/z5 2N_@6;m)4eȫ5Mwޅ&C405`~TNT0B9M Ns&;w@)p=FJD>:.؏^HUz &h]wUXA +aԻ Bi] 04H$\gp0'0O'U:F "%T۱/<3L Ayɖ7*aD4;_aS":ʋzZYڱkmI&Oa7 aj~J&+hm~:2-nGQ >ע,nގ0 alנ_*`Å:{"tNbT%:<:݁~˦G<|4_H|%uu?B{KJTF^M&ʘY6wryIjgކ|:%M҄ p\rh-75<5e%t-7!=qH.[4": ۷TU{ ; ~ىIgYі.{ˍܔ~T.SP9z*+᪙FqB\U/wSAt֊)b -HʩW'T1mBa- czU"b~a0 :WTC؁Lo:iqZT- :Mw"Ҷ뮥/"h߿H01W4ՒT=1bͤ郠7%,suWi>EcKzh _v| o`2dqx'kCW! GwROHLuc9&}H)dDP8Sc KLztΑiۇz\U2XFAp_a#sO^*1K{z. mo5W(5j6;3Flk ydsoxw֞'lfOX vGibVrp3W +bv+g/j;CA~T'd5 +X2v4/YH-noscugݏcsvp~=gvK~fMA‡hܕa{ /ar ?^roF΍s^t6rZqy7VpmlUww^y+UrCN+n)=Cs?PUp\D\s#94x H,WUPejmo3IieC:Ȁ-wSg%``-n'pE^3?c'׳^F[MFlE_I9]5o a%b[^v]qh`pO^:A 8̣PhnM,79Oŧ-B;&MPNBnMPyƼ/|pCX[/[+*uM NEGq۸H6s)/|A_CCGfj1|#T:1DLyӡpYE)'rF9EV9xgPdՀ9窬ik|}q/6J/$*+\SUbWt}Ć`ƆssϟfƘd'+++ʄkeWlbH76)s3}Nɹ͕u81dŽ.,K@THGKz=/ (^-EH.Vneh8'6I2U z_ k^KUMԶtA]=YBrL0ηBœ{~/U+o08mL-an1Po#z+lDp0tA1A4 o` +/H@QʡoZ@>i'v7}puL 倏A}\Chn\!ů*`n & 2H4fO(ngS9=Q3 >)y^,` õdl.>DZm%?F}u*v^.eha#/e|\ oylDac>+%t=+,اǽ&5fƨ,Ua`,sjR`M\3.s Av'%vKeq7YB; #ɶrm؀NGl"P$AIc7K :l|j.S~v+z(ՒRM,xN_C5ԪNCR~q():yj/j*;d*>-XIO(לp0Hgoq7nhk4tѡ5لVl[)LdFX^vdgni$,bԇ0Rć,}-7m*[Ѿ9Sgҙ |0rm]ZgU 64MVWkr +iwWn=r2[ {$r=vfCr~R XCC~CNҀR5d O®:I\gNϷz}Y~9~DeO)x}m&s/pP:/_@=LmߘaNұd)T | 'Ǚҷn7{ȗD +*Rl8 +H5Te*0%'BCgldU},DϜ(uWu_]0ґdZa%6!ܰTאD| +E-[sjto 5t5:\bz0,¤~}'Ru~I{L YqS@ ƛU$lά*ND +Szc`0&F>xЎ"dvs>4TV fG'eQU, 25[bS(R'" H5&yI=vT޸$C~)etA0Ң'L$3GL3 ;ʌuo4.$XXFU"Sb>HM::qC%K~)E }`u'swIoI +utx>n` +Z"{ξDq j$^{,f\jo +o>uajX2Կ'Po1Ktƥ"_4D^^lwC%4+wIi2^]%ohӉW#5Udۚk];Q$ >[K&C2l+N/)*t֣iVɰ+G~a%,2yprtK8is0[>VLR׵8>A2#2 2Ƞ)-A*Nx^~8!=4pfˁ x<+e]?`, "MFE"-*5(װD&c4^Q5CM#"А噤j>/dmyIرK[,,O9%˜1x A*|_:(^49#DU&*ǐ3cAi7hmXLoߘ*h4ęɵY2t#߲ +Ե&R`άĊDA2"@UCM3 eaKA@KMˁ_$ +?g/4eQ3';ÑSo.'{4l&-"u +z? 4s~TX\̷,}Z1(1Z_CSj7JnGY +9W&(CX$H-{A `o@Ч 'c&-1ͪ8qI7ϩv}S (ڪzA7QzgEK|@0 +}G"rVHG"W>3:}, ]xI~n-xvS`Yk9;[cǯz|mXK HWXp,N.&yd%4GJҫB[Ĩ*trʧ F֠Ŝ(Q gaNv,O^[s9@w87In}?Y>C :(6 +$?ʕHɫNGF1ws~wL 'X wL[{OnE3^[T3:BnR͝%mZ晊6lEeTۼ\5SΏrFX U]~GC<vn;*{o\irCH:g=JVMKw_woB]HeSB&eÝ4) +^2VUTB6xʜ?2 [pgn\$=V3A˵.Yj]Ӕv-ZR[ƈשsG{{VJpLS'Mh~횅u=7VӏA7볲Np:qڋs}USk_ʼ~QF^Rdrr,WQ?R5vF_ͳƆK*r5[7:5xvvcpDQ=*00=H}%U˸bˠ>tݡ!k0;Pe.洃XG j&%\3ne"Su|IeFd^mF˛'hc4j/z"8Uzu pioV)W]-6Ëb;̓Ý[9b{h<0l/,~؞Qyjl1!_ʉ5iS8ވv ttKk-gV>XE^_/9JWհN}ug$`O?d˻g~m^>Zf`t5]ZZdihY!=N}jE,Op#] 2ߪXmwYB([4-m0AF,BddL2"4ުJUw5.{_یk;[2.hQ+bV/ݍ^1%OvƳu7iΜz^7Z-=U5&odm,T]'ӲBkD0W|$wZx}gWXp-eudwp:)x +aR;dvL)EQIz;I&]KBAx^WS>2NE+܁Nqp9yYżNe9xE5G! o;_ktdcRdfC +@|6zny0g{HyP^p" CqGvVOf1B`Ϋճ6|hnvUE;C<, @={ +7kgSjSEy#S ٠'+pS|&#F +}8ʅHUsMZ|ݥc˃:AD ҷe#ks`55i``ri OcjmP&9c9\$Ot(Fؖ +pNU@wլRICH#_:Վa_r2T am$у[Fw v1XIB]wKKԥ!LB^i.rI|\G =<VC~PhC@EPt5r\BZ|chM`(,ĆYCÄ/ņopI;׊In$OXk(\epّa=N$8ְfIlNՀWJL.!=xO2nXJμ +f?6i/%}~Ey2XHCv!:4ܺ4Q>}5GuFohVI!hxUTrfdhSn\1al7izvnY-˴DY[Ԥ28 wMGQdidm^ݥ]bTy3#z &гglO2Bj" vU>jؼ^8̆>@`p< o`"܏?ijp^4|f5&?;臭`Qu0.sggy0MEwYB@Fٛƨf+^t.t`HEoGuu{SqHhcx_T$VCBЪs?X<svV l +K!`5q\|x/pS6L& ʹ1F8T@Q'M}SRCLexEuH"½yY24yz֪o2ړt8?8ѵ0ID/aE9^B9m 9]L\v]'eW>w ss8k E9vGe:@Y-*ś֓sF\aE)0J&^/j;hwi=Z[i$ 398:khD_MQڄ>24Cbh 2|NC#rW|j Z;Jsn7Q۽lCgp:ޭݿ;"䥄 Akp*GNrcx2Dm>\3lg/JzkX^;N5Qr)@nm1e?L@ym@P&pi*0 fTM6PC{ΣֲIAq "=ńĄiqE5qfաw>q{ښ7Ε30ݬ nЊnnY܊Z=T0eKb+ hMW76lW{x#"Zʫ&NDoޕ[ LՆ54ߤ .6e]C@"[@싐!1ϵ@ =#XVgyL^w$e?^^ 8~_'QXJ=pxRx{_ꟵZ;\?XZsWk :DcVxZCe9q9Dr4qu~$˚Z̿IFڞ2^4xx郗KYp4QCS9s!7X;tαC' )a dM +Mň 8=o_lճ64y47ϔUO" Gz:Gc Ü2P.BNIqmݥ +J 7L0-1Ys[9 IPr ݖV0Y z>7PL0c@DW>(*tTbDӢ?(b*~g;TN}fM?8C&74rqSc2nXxOHډ"+(yg n:q`ߙQ[HԍXx)j:hO"ۏ\Mc%f\"螜}ͮ2LHz-o@ VJHS/21 JibAggg4%=}9ٳ|T5_^_Ց&.uuBoscPbmmyW&Bo̴n/6sC>`D?TGekPmAfDn3Kb,hhje&:b:TGt6MإLl޶obTctr !٢*:^956 +)E17  yjlYsrlDZO۶>f(wBϵ3\haxxm!_1Υ0MUCh> B׼^jOx(Ds5 oLe&-]Ӣ-h|"cN}++1/s'bXL#mq.&v~=+}x6 N忌SM,tX~\x#6~{;sд + x64\ +x$t=# J/%Tfi-2X|֣r?!]{dl'˩y>ު7Et߸IN@Zu)xr¬&5G9 SJ]M*V>6q+6CH;991 |#MV03snȕ;GUf5[r)[0H +(^T+/!U@!|6eqSV\h*N=Fka%^ްd70$uِKSlF%$nvܘIc4ɁzcSAƪDLޫ\(!aa꺖xjlǯ͚\4o.3F1".ZrTaSh?Ҡ)Yq̛@ L=<{swأ!ii=T| +?*0T8pnc||ȷY +TbF>fnKn&_Ya춭>gjͭlܿ>N㜟בQ_V:Xϙbfm%L@/eIG4*u\6R>n(:J(l&+|d C#o4>^gcSgv>h +endstream endobj 60 0 obj <>stream +HWkW~׺?B  3 /ݝNgLU뵫QwYSc5*R*'4j*QL׹H,rf)A[ 0䀙|楔in+Wyl](c߫h|TZtf|]BJrJK\*Bf̨ǿ(1xhV{gl^IUЈ!R_G:m oi lK^) R1/ ifi!dBiˬt\Y ΦiI4UB>9e͸+. ɗ)[d^Tf"?UI341{Ւw[ +p 숷.VMWq$sSM<#L < ժt33>FZxş}_.}A>=꫋j%oZQ +@[X)A;}m໫ϴO'jǗ z߮VgGO\f: Íy?YdÜNJ9=)޴!ѳ90VCʵW.fnpo{ijaHI +;VW뢲kƜ4ujY5>Hgi5q/Ze\g'd̶1˴uUo?;v"˙}斜i}Ί𧚖Iɑe+!`,ؓ#-|B}%w}zX{ݵ[skUY@|V.PnT@鳦-ZA l~xr +tHHu;5(BrAT?J'H[c{Ƙnud.XqdThDެz3s{ 1{]f/q {lW2>p/G> .s3+k_C|K.̴u7Y qH<}@)B AєPm"q{TMh} Fkm#٥_ .Qz|A˕Rg{s!dwaGyښ +:+绾r|3 +3Ya4'oL,\hhtȀ9[@-P0&ld-KXStZ|q 4[W94 {(O5iيHVW"sN2+4"V;Z 4o&~!w %HV*l?H +k[F< cX?פЕLtt01{y ӛܘ>NJ#\QAubda;8ה(\2w_fi7@vbǦl:yBPtoD|1VOπ݈P^"qt1܈ioh5{9.7"uF9{ҧ)sJ`2&.K!!FFQQ&Uag[.D%սz^IcܢPaAU 4?ZOvvLHaAi9%ބ%[3ʜ3z&-C)\mQ:%.nxr{є`6;H2 2 ܩ 45%stR bn^7.v,e : ȵ$/[ӭkGeзhғ4G_ȰiI<82nEήt"wq,ny\JIv-`u-Qy~!E +x5qsg{&4Z=qŏ_МN Le͵W[50#p'i/2PZ)y &i!@Y9D!Z*ၕֿCrYv  {CQVD(NP--d>PxQh-w_]oq':f&GX.`#{ܐǦ''B#fɠ<&*:Hؽ~J.HnOT.#؅jmT'!Pho=GGDY.AWy=Y@"_rUnv%[ovEf+ +XjF~HrA37 Gy:\G Ԍh(p?2:! +f:7Ѫ' +ߞVD~|e8fy⺊lT@ី?_gAhi硊 +s~|2'(NPl3\@ĕ|4ʝڻʹUH-J\j@d++bOV@Q +iN?c>`a{#) F/sMJ5S`i?6_HE +>#,DړhҾ|d|=9ClZcܞK[TY)4C1L3~QH1V7!悳`KzF^ P i@.=Ôi +M߅ !ZXYkXP{(:W~oQ'`8gNBU}_4ήVCs*J\ $,*8!" + (OfuBw/}8X˭[ :ö. uRRў^١ *xkfmwɲ@Ne,`2~YRv9b:}Z6Ocr7^thW650"Nzz'*+v9jhzXe5&BW;"vt1Ԙ!@[Dlctec #Pm-o}у0I1&' 4׮s2D@O2.*<-C&'͍glpBfz(5aiq(r:uBQh-LJ]._kAa*N\}<Ɇ|آGK˲F~jr8٨QtH͠V9K$HT"^Zu XO F(5%]oPљY*X;  d]5Z +kZ"ad"MUaEvH6Ha;az`L/Ryl(ŀPjKEbOh$9qh\fljlSҼG /0=tÃ\˧i6y ;/:*,!=4K:n-#n>7d f +Qz6([U[bb̘T +zКMyNPb}N l^j>LGβl=Bwk-s&hoq@{q/?PlK:hptiUx؞*σMllYw>3!eÉMlTM Qj^Kn-X%ՆEu:46І;& ΚihJOh_IԙA xAd*p5h<VAdie .iCeU9.\˹r,:6uC+MwWq ~yp2cB&[. [yi=7Ac A#5=R3zݞc dӱ9Fla /Ă!?%O_U7jAC}؏0gvĮs +Ĩh ?m{`8S2H.ǝ4K~VEҨH.ⶼ}QaۓRX^2{ms A24GCpz) +Ik1$+hnrcr5]$C)+!k;4kVʂΉrhd8A^o9heZKM_k$p4?VaOh‡ +̆ +`qwl"nB?6Aڻ`KHTz(5bԖj-i^ejs-> ;[19ltC?qkC1 'Fz#|D9<РX1W?Z}o<| da<yaaq/2a45ߑe*.Lj!1Vx2\ y 7Xam,E>pJ>a0Kdq?Ó9mN?N~cċ ޙmgR(g֚}Ӑ!e|&+g$+jb(:Q ?md^z +BA$ +~,zKќ. h"Ɂ +2d뎴Zq #ENl: |@@k!kfx:,?r{F( + i*iM{lv8F_)2ﲟMŨT8rpR0ӒNkm%XHj͚.3xy*>X5HK߲+@EwR' 㻫>=]en~g#\lS'8ET^aYf:WWW*}k&1 $a +d(*9~1ˬNjꋔ|Raկ/|+։²~LW;׽5*,B^WgV=>WzN[o Ԃ3זP..=O+E>tGrP-YIh =-t"K/\k=d%O]Mp EȉŢ*z_VbwȉvW;e&cb9sZHE`i*@<6 P[c̨4|61M[<+ոhm dd·Kƥy%jzE@w +:5KqݞJ~jUdfZ},3 + ++ޝ9ta>4bWX)#}8Hp<7T|y *ܦC/q{;ӬXl^YNyhMqDDUtܴeCSo`VZiKF` )مDheE!Ou +>纚c; OuVzN,yñYJs>]>Wr"sok +L\!냫y{b7ݧ⓹hޯi+7~*}jt f_e__K'-+G}`4}#93M f2> )RC׵\^ Ʒ{dt';j1"̈́ߚŭ"w>S!y1Sޞp+§2zSLiS)F~m%W2T]|&mA 0S,ؠ"p)nQ7V&b d3j"= BCI~4`_]-40U$"Uy9jRr(TU}:O ޭч'fP ת4/@.2ss}|qV/P#VnY兡e&cӍ1raOx>B{ZQH1Dh&AY?cvY +EXn3 _t,t>Cƭ2!T pTrtlB@Z4{WoԧQDwV3|ŏ!$&{wE;HھVٷkM!lܢ}^z{vlFΓ +oj‰P) Ld! z'S qk7~1fd:! N@YNRM;[~xtԫZ~h#ȍNXQaC@@2ΰZ:per?}d@׊B.t´zco rtsB8?&3FR + ) |i&ſ9TgEW"1= YgDV| IFk?dm~+F~btኁ,2V;~4ipCH1;G9+9=fڷlu,q8S7a N3 '} WRL#90-4;3䦣xaE9S0xsw@; >\MT榽 q{)%7KwWo**Ed)]+-Dse\6NhyY5JrpߒmvV;򈅗J2*O!K[oO:R PF䘟.v׊,*զr@obLm}ʪGֳrFYĚs ufIΟq`0O6<,F̱`-Fy99yccY)BUABCCi5eDOZчKDcxiTk  mx +>3m\P5ƹ$ưSѬ@*f?}pٗ+Y/È_~Z*3o/KObŶt!?ã1dC!H6DGٗPy~H[J\k?|A47m f@9Peh԰pznx"`Q!9$a2HE/EY NI"ElUrFUU-yp!%0P3ja bȨ+c3-OTS +u8Ѝ9a6+GOuGJו^0a ,@X20d؂I@Suߗ_K„7SdKnOMrX~j.̙x-jnޯ&pGlE|?q xCbUL1x뭹gpsbE˅zDe7 oq ( W77]Yh6~W5VL&im?f nbӸD[Z+||v@`476 ;gU.*oQKG)z]5:5s4U.BES,~& +"p$ +"@t(%y:A SZ :GI#|Az!J̢ح+%`CsZ Ics;̡gxÏ8 | L HӚEnSn"҂mDGk +$%ɖEpPv2 }y,vQ8+7ԧ6wZ昍"4"ih詩ſƠ}bha8Nް6(XKFE:A@;h|KU;w2\_;3zᯃ K%"ҠBNuXeX$il5zGG ilVAؼu(>_5HS wNOmS<?כm0o 6VxH tO8!Q~wC ({N3DW Z4{'hl~:ç.9,pXŸq'pi>"VPR@VܰQ^fm+4S0AvW9s$b"~$G}6QwzuURi +YjZ|SKA6%k<ݰsAb{] /=7E !ALFuq d-ϴDKW7`*gfQ74x,IjO jç9멛tbfO-r @vøzĿ3BZM_&^dÙ? y+ %y_$ 0HQa4zfNJA(gqwP |7l2 +g8ɷH#5͕`Es1GWʴXSԅ9JύV%M!JΑC{oC{zOKrE.`4B뀷:k|Yã}ky"y4iӟ_mr  !K,ZY5[#Nn *(lj@ֈL+LU 0%X~apR,Y]&> lL)ТQ;Nh$7v@b/Vų48i}% ZZZ rOG71p})eh [u\yTh1+z=PKraJ_wo*k<)/=[_^ͥ kڻ7$1)O?7ICΔDmc[>Bi"^jkm#U]Gq%ݰRk{.gq5=Gw[MR2H}~3>sMǷWSNl +AtF0St12?]Zen1f,$/Hik.4d< ~ƷO؎pFo,Lntж i)0W${Tf@r rDzNޡh&ЀLFEN *(tK2Q +e*N~4,e +P;P&wIif;4+;-L^_CAWTvBr@<؛ S0܋E}-; zSղgz"9 }5LD!ap0wɴ;MLn7[ǡlDBCG4Եh+g`/!־H**\rIeqZ~!qA'dX)3ouH PR^H(l:Gڲ?Ryl=Bi` J׌MÌk&6ZȎ5iP-\h45\(D۠MD9j#Cb|aDs4o'hdIayw$6b@6ac^0 yaHR L)m`'3U*FZR5@D-tykI# aB#G&K29LFĔԯ"*VAd?FS˥&Gi@2cqw3$-ēl ghIT ٓDIܟ@(V d"zWe"4hZd*oMh` VL;c +a8E >ܺQRP'`tb "@XHUUI;ǃUrW_;XSUnuQuV]8Q-H7<`#LVu7:]&Z7ڎѻ;:|)Fau{)eWzqϞ z8eI P{bpFGu?^]s68nNC7FܷzF'7o'EF>NV/Q|Ȣ*c2(Nw/v h&+x"Jx/4!kY⭞&`<Aau]{>"?m/$Qw>[-`~f-lADVvI!ҁa)Eh +endstream endobj 61 0 obj <>stream +H̗koܸP?,"iH]6a{(xgci6"8MhH˘NY.29eҷl:-$e DMͿX] mgYZzus+ޱ^[xesn~^߿knL7O[e=Ơ|. 岽[(}<-~oc]/BI}n-51vBG҅PB/hnL&XfBUY';b$ $MMu;ԭv{4e^v= _w!M4 +c1eiS=T\f<N3 +uH8 1ojD ^ oݪ;;>K%)毆r\`hJaq =vm7z W%Yel.B +uȮuZ?BL7ieV7||&雋~9G/Ir=4虽}/zt_EڜSXf~￟~پ<U]ᩦߛak,4L\}DKge)Kϣ!ahmNG1y]^m'۵Cu߯R!.dh/zu74ۧ?> wEOi7xG_uKNdW=Yσ]yCz~~xzn,W\ff>^d`QDeny|YF^$KO\K%FJ(WL:ʨc"{q\6ZFch+MeE<F!`k74 )b7s!ƈ~!ʯKﲷCݵ>O7K P'HE41ĒRLSΔSE55RG ZҊ֌0ܩgIu3 G̱b5Ŋ3ι\voY)rFXD!*QK"-Nr)#4BuNssMnsy׊(J)P5Ѹ&ksZ[t+]+0 |k)LejK, ++mn5Zg [Gs 'A`igut RU+x L)`@—TS%y%\O<|,ᅤȇYVm$L"(c}"bց/w_J,Sbbjx2%<~7R t wXm/EwaI_ ,CI^1w<PD6͑ʲ9F"N"tC6CQK??7C4FRd-5!#6 +I/b'DH#₹vIDe%l*=cce]5>+Ax?R.|B<<9G|g0;(&ՌnOËΘO{^ 9#޵=̰3܌bFrb|W3I|(Gb,rF>C3 {%=D^Ibޏ)֌?{/]Dg_eH𿁾Ki!)~j̤ůgh *˴Dc9r`LE?46lLWIE}d%UK GG̏׎b}rfw^^xG{>h!6F{)~ZvCgf(xagd|"0IlZՙ31nc*f9]aR v&+3KeڿlML\l55Pۘ/i[v{O$t$[ҵ#YCgC ԉ3?aU@w\!@,Z&QXWۂ]z=js\&WU8fk{;1H|y' +tjqŌrqzrݹ#]H|]Sȯݎ/˫z{όd2LM,Qs94Yfȯ;ooɐ3>}3e*JR=5/9kZl:vёm\kNa+K5J;v uDC쨙-u:U'եՏ5֑5_lAaWi(c ]"#],H(hZ^[2ݶvpQM˝sS;CY,#-jr28찒e(c %T&ĩam-[)E#QbD@2ʾ;',$0!Rdq1LV:T 3ʵ*W6(-~`v䊩"UĊP1V?yGs0Ա>WL+BűXM#8aG=aɱGTSE\;B1xx'P{wsokgc_$s\B=6p0U[صk+itƕP,U)W&?6:sWpmhT +P%ifߙoXmש=yվ;7քe$6=?[6/˾WOKo?rW4ЉDuKD4Șqf!C{:vqH#$ L9+cC}t|DuWwV7_uGGWF8O%պ2,muxN.2?>1;t $6ƇDphbΑ ыw@ +b3|1wDGQ`+#;"cvtBX=#ppQ[d:E441Liud&LL12'TN*OM9Q3yk<>;ixG2LlJ LJb NX?kPB }Lv)3) +B`b?놉5 N0 kU@5z0{ve+lٰz,7ɏ';_󬜎 6H I&Bё[h^ImclX'Č銩iS+s6g#7f]v?r5)7#4 RAn0 v76}Uq׸ szx$rs2h +4UV6aE{9p_dn#rvR6QQQZQSE E2 *FkP +ěD/C s)ͮ~pcӧL-=/f<FZ[8&K7=d]^IEX ڞ{nH7@xAa|pd]imzfa,sŋ,>JLȏ +h4:$\}Bl03&jiFW4"jX䐰hѓMʧV)r 4p&@(km1;a^`ubOW7ՒnmM5{IuL`Ə?YJd?~R$9wm({noP*V|WVb ߐ*`%^Z>||L_^FY2s +Mhnz8k>~-g:v>6H7ǪJy]]3<3_SkE{}qVμ(\iۏ1cEnkHxs=0ؿ!l/'4} )=ur/GG@ -5+e=>W?^u CߵG`w50?r)Qݟ32f/g1cU4grLD[3;fTB_ :醖C:6@?Mh[ ٍ V͞U6\vꝩf/2d3b&3Ŭ,h:m&hlMvYE2AqVaxǼ>}W]<.R@ĐJ̈́xE!H189.VPhGO)$|8 + Jh9hdrvS͘B + z4#` 3q rÂ)X-X9 +^Uhrx}ffTNؾ 3aiY'^0Z /7a<)DcfPd6 6zv hLdh~Ȅ8aR%V@OT^JLf淶 U[W̆p#lYʥ\[hJ~/mYuKlUFJ8V7OMB[.7Ln 6bG<)Dl'icX:Tt_> {u@1nw'/(."W,\KT]7w/ bEWj.re ➉"SU!҈i#n b6tj.ۥ!Tf\ؑvpaj۬n/W+.R7p77"C^9/2A* wFx_^޼+Χ =qP*[.rQkN;(\i0ՠhoϧ7JBbGZgs +Ng_g5g=\-3jF⢯CFpoOEXX2﷡.s?^Zu}~X_ﴍfTތ?w?~|z\۽oۧ_~~|f(`q UG8`TYW(1jW5 #ux@Kɜ@CJʥN8Rt\hSarME|b_1 WiM Mf ?dͰNRb A 8sdIխ^1Z Gщ_կXZNqAFd2|½ + UE*?k\i$=?TFyC|%l#3cSן'uSrɞJ!i`c'`IQzU7M Hﺔud[p>7l;a&>^Sdxb?n!:-2֧`+P䍱2mo>aqE||گ/3Њc6G"뺀y_ RjkTJ¬(Bc^(]JXKKm 8md'd>(*|(i/({ "P^A@9򏚐%$3q2Aire(Qv<'RLH&p/d@\J9U+ ʵsPqLő3308I8>=0b(MC0\ 6yexkŋO9l*Xqs Z7WJs-*7v3 :w^`vQ /CսosվT͋ޛIrQ ]eVumD˛ i׳jE*Z-MPlܴi&gV)O4gTUh5$ѐ(G#*mR鶫v-UWFM'||ny/OOߞO_#hXuZCW9rTL*٠]潋k7+25X7ZjZ$ ɃTmlW}^I!ebwˏd3xP~|~~C5h:!7rGOieE0BV8#AYZi V)Qd&˅JQX 2>!\zƭ ol >$QN ,l f/&HU!J-wU?c&(9fȖO ,3pSl5s?I$UY$);,=w޳-nQ\l 0BK/JQo{i!(6pZĻirHHs-k/Jp"`hBf<hnPqf-wŒ]OHgEq͈ Q)r;E$d4z#Ȉ"nоZۅĿ!#POvCr˰  7DRŶVQD@ f֠;X 6%61eFI<F_BXu$[a|4WVVa7cfT)w-kZ檲 X0c؇FIE"R|Y5aW?E˽0>V?X\^*'o)lM2CiaN6fVDe[9h^anM0P,!bwN1>pO %s(iT2,.V 0##Fk/9<~QW($ao836Ѿb#G|[DM^QlڨHHġ⎑Ƹ2d`Ԛw'nh<7Uu>N#h!x 9B\ i !"ѪݑdLEa1cF108́ba)5 +@PD r^J fEiXO'[ar^Wx[<ǏQ=}k|;yxA0ǏEDwXD?q0a|81w]iʽVRSNFuTQoh*nDU.ܒ%1KozYyaJ#fBLܣ7^ 4i>JZL. +oj,m)Ocb Sknt=3}J?L{o|8v{ gy={{?a |c))ޤ>vy/dXܳ\5뵫5Oq0<àGX XJ@4lz\wh@1Œ%a J 2z*T?WM/4)b>NO xcn HQ&D3)60]5`0!cVjP`|0ԲKIMoj:bb:F5s4I`bWuOqU/=X6XkWk7RҐHX; +*t\ +qzj2Mfd`Z,e`0&)J4܅@tr'TRPcmr>y h}?W2Z+: E!}n*:TxWn0/ڇ$o\-l. hS` Hi؇4c4qXӅ+AWk3= 5b JI*Ѐ,(`i_ [M!>DNHCl:zyPKSq`)Ƅ"_[*GN(- ]'H' ,'zH4㤏YRL,5X +,| 4+4zr*rr"-p!,+1EC}IVLPE̕LDhVW$w'h\:!G[Rd_^?|%VU;fH75!Gty+L~r\sx|h1Nx8ex 38190|@QB2Z?sQ}^t9gl8X:7QP#B@eUD`cTgHw8ΐIxH1r!0?@c1q}zL`Bq^6W!zڳԛRkP5JXҨRjԔv97*&Uq`vHUӷU(C R%+OVp~h@[4_c6fy<gD*Q$H$10I$8p>3ALȬEvO v;`p UPj"#ZcuA*p +D8V +|CPW$LQ"eIal223.* i2:crAǁHa#d.C1 H}FiH`rԂ;G\9a0}'>n.$2 +AWUnzsӍc IJ^u-4 +׸fDޏďFFdV.URb%"3QnmW{yȊw<ROjtH"Bׁrb9&ѢD01qs`ʈ.K”L,I}YN,gh} J8G$љDY"t`<xS7Lјd10)#yGN3%`4΂.7.,'sWJ3PCH`Jybdd'35 QFKC#O ]3D $э'FI}$IT$FzU +IZRyrթM5KYjL]_TU(u-U_H[?ںVuj424aU 6krs=4Wh4ocH@*`晐$ Jdx(YH<},&lmUa},xL\k0 35tdL=0WhƲ/X8>/(k$qM WF/ ѻ0#`-oEf[x]w5VE*rsWރPhlCDgBo`=qY3t%u0_d=3Kp^E/SԴuPcF-i\f}Q)=ZtFWx4}3:]eճ.oo.w7wK~gͤߞ{{{KՓ_^7jz*C>{v6*#v?t{ڽ^uo{ߴJ'jh]OI +a1RM/hR +D?c; u/^AuOaսa AZk3x+- +':x,Gh f b !Z@A8=Nޘ& +AVA&Ҭ6K44Yߣ5bkr{ވ=AEB?zo8,xXgVg.h:W4E"W#}AmuGB8CJ%6ƍ}Evmq,̐ʹsKzKBjB/vIl $֧_Ug%j2@̒XE*'%:NbLSأC*3AШ^ +dzE>ӏn<{xu|OԡwOE|9G|Fѣ+9Ef6GdkWPzChi<{"0RGSmz P7U9WD_)|ܛZzjЫɦ1M; bVAmIC?b^1cя6ś> jfyb +xu6Sogi@w2ONEj&qfq.u_jdl?]֐K M$F[lDLG? Sn^n5u5{W~raC:8_6_az|nbFŲ'K^aIrM'~+<\c_dos>p(4? +<\?ZE5DFw%pX~~;jįH;ċ\x~xA?|K\ +?qt+u{}o p EڄnSұ +?vu{j t¯Wv}vq/*؛ܮ1];]7lw|cl\+r=!mhޮ1d];5K5.W+s]ű + d!@2eevr:v^OTWL(gihOɗNGv۪K=bMZkj2pW`[[j>)^"WCK{OA=|%TR0efb +b3\] mp R{sWjv#䷕_qP}TKU?+i["NQÃp\];1۹%N.0(x%"]]mURR4=fq1 +'^AqzDR+Nj['T cbjKKeKbɡqRWG& +9tꚸ/ă^%N:boxUxp~A0LY>fwn?2 rvoE9#S ')ӞSg`Y7_>Z?86>^Q7txQV >fFו?;xo7ѻFq>z֫ K91yA5 dWtҵ2,ýGz,laUu1gs<u: ($L:f KiVU.e͵V{Su5>8ʎKDTQ +r#jm:4BwS-pù{w)qpU=dl9э\7Kp=:zFRTT5&1 +?;=kQ9h[S +aŻն(8lEg|IضB5AcTr52Ugb+xǂ8-n`,оԿr4%A7E?PcmR6IIY'UC 6yIqglmH;~/ {G"6v5\DDMZZq)+6;rV[؊,{`^kt 喙O +tr/uqzUVa8RKaec̴oAe56%}iv +*|ms&q]KڊWC ۈE; m5Jw+N ^S$P/p ? +Zi0,o%,6^3"g#ԑ@pqcT"M#qǴpg4WrT@jGS`AS;;9[< Pi-B#f'UsdWvV9 k YnKi;K?_zo->JˈK ŵk'T$珧"`^,IhOw1tML~q+П?2e,aąKB泊x_B#h! ȴQƪA 2Xց *Ueiq "'8>9NP=q`R;}"Tv[^5tET$Z6vmZj nR1m(M.:u7k`$h4t*4ơMn Rl4Ku+Yi`9j,Ҹg?+j Ggn(1eZS:?KHAqW LqXWB`J*aX+4Lv'gzɲg>xNj,MqG3,'n V +Cyu/S]E(h9!uޠԝ:*F06K4D" 8yx#_sb].EYқ2b_|ؗ"\p~TӞ¦Bgo ce]$te.8 _M KGsJKu3ML<p##κZ=s= L 1*mjeu!6t|7(ɽ0Z(G +<6?Ym"I;I*EG*zNϜTJ@aAVj Fo[yh%{0YIV& ھ9Ic؇YWl,A/!jM?xۼY3ŗG"=V:MyyaDÝ2mj\55 +endstream endobj 62 0 obj <>stream +HW=e9 ̷j ![l}œR@.qVΰDKp~#8VP1j?db#/>_u953E#.s^ }T]H!Xuş1A p#GN{ϙY*ץv'7lB ^ǹ^+:L,Rba>KFu 6IpSuJZ0 U9oeهyX_wdMҐ0qI <@%lY$nC޷8-pJEtE?} úaOfL2tfƍ甝`"5xhnY<(4EO[NjvL,y}w/PVp~4>LVPAͤ׷x:.QF,4a(Ru)\;[FOLm=m,;ᕣmVKրGz1vQ.KpU'}*HKΉ⧜wŔEJ< Ry%>Zq8Aٖ` gp_58HFvAxtn k5z#]ŤL8^n;^>L]4l9vϺՄsnʧ =#1ՋɫG|MTêɏdXUgƑ>ܭA9vX^^|ӳGbsһ6 8y6S蝻{/RL]^#u~G۩L̗Lg4*$IQݞ® +` 2Xi$euydjlK%.hM;ꄝNoNjvf~%NC$i{]ڱ X a^m\jHE;^yJIa7iJK4+^m㭳N0D@1..QD$S Ǖ>g`XnW[lm|V6bpI/+8fKӓC]Uۍ1=ddz~G<߿_?qBh$oۮȃ$ BB^ =ʿs;B3UobM^,# qp#gSΠpkst9-d'1 w:qv׍}"zcb8Ju6sYZ95~jS=i9 &0N;˹a6!]L~psg~.=׎9iQ17^AKj#M vrH #k8&|:cHpNn/vkw+e<+~^ws9DJezL[v^+[>UVC̞+ۑ%!MãлwIRü? \F X0Q, SbaO[,lk=r0URq%W5uǝn:n +%zZ,QDY+ۨ`.";o%[G /G4j|DzGz|NcIW5[,=0j/?u*r +Zk,EF99q~9U=v/4eZ-B%'-Ed?[ )KyooO-^u}aN9rcc0]Gt=CzQq7^@u R6 dgX̊u6Xe;5eP[}=I6Ay3Z.uҝ Ma'ov%dJx.Lݫx@p|vQ>7Oo_4wwؖjj*.W܉JDDZ]ш>'V:*,ca2!zոwcJN_oa?CHari$9"5D1WDYe[G_{Y3fpnnYgO:݉WhYooer_{f5p4& k̝U**G'X; >ʟ1`_f6nRU`VUv-"gL.cAk\Tٽ ҉ұk}jo}'{&Cd(CUu#3I#/ WzmWo81r_<%si[I+*OϾZ (rjcM +u|?wHT`vK~bOR*^#MQsh_T91#0\uJ@JVm;xxEKpx3̈́i~"|&$xV.+pvG^A&ꊅaywKDNtx^2| 7jwA~pӽaԗӐ26E}rQ6>!H*煏1xM̍Hs3#84cN$'T9Eb=U'8VL龗|oǡi~6n9"x###zQÙ?x=>kCGLY2|pb(VIw#Xmhô'Q Q4lQil77;,&FaoRԧZ{B|l&#A- RKp/)Dbw%V7w^Z1s^_Bgg] Ͽ} z;'qktgMI":Q3oun!k{24`~qt:ȃ/;5qL0h.sE?Ƀ&pg<y6#{7+CAc b10Z(k$^:̠nvLES>\?E) O;; Ewv&GVss|kT$ P[ 0f%0²8;V.\ӻm_P샓&eiUV&ޡ|ïnǩwhlvW0sjF⫞y݉y1Ÿ*@4Ŕ9r(i 1Eb뒂rK,R^n']/c; [|t,-D_`HV1hn`?w@ih2CCio[Z./bC }7@љ7,!W z-󖓙ʠ M1NNa6g+GIqںlH rPSg AsU o73$-Y}hFŚ)몮j ;W0) +@3;fxH;%^+1m xiNiP𚵵-`J]~^v<2w3BWX폩1~ϙQ7O@s⤸N3G(F0 G3}GwU[Fapp:rihqobE-prp5ȗvX38p<;#9@aA)[`kwkHqQ13V0E0Z`i$$OXZuΟ)I}7Hg\np PBlv?\1tħO9\o xLpsw}u7]sФyu8_T: y8YK;,T7L\5.v>ێƽƳ!m%|=L3 )G[i.}LxI0IM:a?w{1pxl#yi`mA:~=ALtT@+%{qJRj #x k &iSHe+rFRouoSʻJsŨTHZW oyj$ZK`,7!T#!vuX:W^?] +PB1LO(8p7AAcX MR#O 5]sF5+?2&ZV0 +?&]74`i#Xy8dmFhafsjXGE [`RC!,5ú0#EyCdb+%7Ӹ{BqU([}B + a xV )[= $hְL*BèF3=k/dk`9B5;倰GԃV jH[J7Mm}^WIF2'yXgT[՝}G_?+479U7>K捑{ݡlt8}.4hkhݕͅ'^lvrY`$15BDr_|?1rPq j`ָUlrV-??xVطdA"iR#{/7,?q{/pFE8g[A`'Z$mׂa~Gp<=?/^}-;]d뮵MU аj^J;fܭHrUY]NWX4~2dG;_ "7`*2#DɌH3il c5z&P4Ҽ~.7QIΆ/HAՔRqT̕lB`&?= ⥷0YLo%k"i}v1-KR(,,OQ'|G\bl=f!A>֪ `z@[Z`ba' ֺ HҘj l{+bMpzů9<Q mQ,GhV1wH{ΞvmzR?6ejpƾ92Lq+o/W)c1bw[$EAɄ s>0> lnC˔R.K}#˄͉"֑tdT*Â*IJ ! Wu~VD| A Pe8xYóe)i%Sϛk;R$0{ydzw24^8M'Kz/9FF~4-ƽaI'A< nb8^GA>gҔ) mrqib-rTMƭv̜ǻ_[M>Mi h8"Hh\9@Coc^j\Š 5o+ղ\xrB=/z㙟WVW>#P|m]|FUhF=zE?޿ׯ|O?~zzϏ_oާ7ߥۧ߿i}[?ӿ|?޾k}} ª(įcGQp_m\o]8x: 0=>چ* (}ȥ)]X~ öQIӬM \ ztpmH T Y02lp-'*À&ÏH>i*Zڬ[`osBϹHͥƋ@ Nlz6:YHXBsbUs-wi׺u=Rݾ1cfzx[ { iCP3 cU^ڲR)+Lۜ"% \eۃ7Yk(271Z+oc n9"@j9ҭ PP%Ҋj˘nڜmaGt+sΌ%2zFe`dܺ\B3YIlp%M6X/r۝nNLK R/c큯.8;^pr!vr21)=>v&5)^N `ϠK >}8vNYk8% -$lu`G '|R )D"j nG* i,R4fE֤O=S[6{Nj;6~':>Alk{vDr\{z8%-v|1lyMjԕ%-ڗh\*J{^q@{dk(ۅ(§);pZ5`O%Β%`ڳqH,6{kFTտt:hRr=cxdc +Č3k[rRjx>/alܶ5m./qp}:0^uqe mXx[=u?$eC}9g^on`6:<iC9ޛ'}/p7 +=LzwOHۖUi[COczd &O)mڂ`ɫM4pS%1q r$ Hڪm-,\k#5W1)`O|*q!>a\Do,vM@9<gƭ8Dowpdg"hjh)Zq*=>BF \vkQPm[Wnqbu]T@BiQ5o|~M(=z C){YxZ8~߶K[v-}(MQuZ6{8SVXr]>WԧɛdDXx[0ge|(~ vծ$AnrW6vp'%s\<|sѲ)@0|^e[ @?Z.7]!e7HUWb09E?ʘ9}J ,A%`'`Kfi[=$?aTtk17#x cAhh~F>:&Rmٌiگ*A:ѲΠ n6bsGr]*8:id3i>-'Slz&O*>u0T<GBw7';PZ}&n.gjfHϺDdvk_1,iS:~r}&R^+AJpO-x~1n +:Զu7 =1İ*R o3Peg xM@lxJH B7+EQu-MԞyھD1P+M6y<3(Ij{uE"RA=4sX ds|x9W~ZRFͅ+\4ρ(1A-K,:6`&tFᜂ3Hr/\CkĐ=mY!BTLܚH#Cȶ-cR ) +jqg1 U{_q(O Qa$puM !C%jY]Vo9=h"&߾b/B +tkZ8Zъ=Y E 6yc`bO5itiԏwyͶ`$غ^֖޾v%L;v,W +v }`=rZ"~sE UmQ Ч X}&ֆ2}x|}Le^5Nǩd?ιQ0#>#]FQ/1j1kljŽа@gYRP<;MV7WٮoekrL?T5Q y0E.=O ?u)%Z5=<+ҢNB2jwɍCq^&׬}iK2خhR{Mej϶n[v8,0J[+CDPݦWd>U.gK'rVOϜW-| mzܦmVr9d` % s;qN_޲p,*PpTZmg )dr}3avȞ+ԔQ7q7 X7 qnV,2ȯtʑ?P!Nwkk>a' 7 *r P7%Yܩ~}̹a(辔Sf*hڤ 7jdVhb 8y^*c")=Fm^59m wu4lK[wue"YDRaM0T<"}/´B= m$^~~KdF +GR]k؇BQ UyƋs=Q\VۜcJFwpW] +CYpNPDS:“ Nڿ}ɠ|4sk߰ܟڜCW@l +^'VZ=ݎ&W1vd{^7ff0u"0~ 8= e(d0@Fp>^pZ~$ KZiĭOf!T}i AVn^MwF+?{ղc7@sEJ-5=Я1eu[Xy#xA6R%B#4$8KA}Z,"(=2W!͸ӑվW"B9\lR>ƫ_T Q ܸB,.7BZ{ NoEcdo>mQ6ЗxaB^x4eZqaI5?ey-c l c4Яqr` h<'bcdٲ8|*K'U*B),$K!-a/;shb;s+[cQoxલZ5>̓}B.huI'ȑ$L# uSbAA+h~k'̴8r%^{ML"xičY|Lc [w/BkjcC,5d# F>{:h x&lk NM2r (˧P$r.+AQ?@$6F<{Qi o4ֲ8a,/@}toqޡ$e +ۛwP0ǃf+'P?10Vo8Wh:|jۯy=-e2E# d5깜ECEu] @~6bRjNeh`! Y |MK[]seZ2j^2U_ANiHm) б7$9=Yw#|L f!vQ/%d—|t +Ԃ f[}?]]sN),Dە-G8} ]m(Cu%<vfN1  `[%,rCaYt +pW%]~_c}CV[ ߋ +lLK*{H*v9D8J;NM҃glwr8) #ZfϵLuEVpM{,%2_Ҧ cNbCRe%R{\YB)eFca\Usء[/ pAv:֬߾okLDdm 'E78]W;m{Zs_7)6UJ Qur;Ğ\U(2eƯ Ȫt>XZR,~N봇 4f1 R n\ "@j=)&!$ax#涊<|F`XyQk.7I mɕ4r- bB9#{M|x{YB0} /OIb'$J$aWDg_1(ṰbJ\@`:!%=_k(b+C ÅXo3_ +h^Sی65,{!i@XP[I;(k1,faNN Xam<>iSHVf2&nGKGk_"u;3A=5AF.\'{jRSӷUmM[ׅwd/{RgɳTRsg/a.aE~p0xߊ ЯȧXAγlnM<\V1n*aAUl%[{nwq9h:FToK\y9߁25bu؛苹>^B{d7bnיpR! }3 b)APYuɱ^5(2pxF5HUDE7c^rhaO#u}ؙ[_k$8t""3hT~Nv2@PX{mu#|J˱FdY!syG;v%@6Lf>Fo>-$5@nw Q W'bWg# ĦTcɅO;FzÞr3:'xJW҇"L|f1 (`bjMbn"}LL)%e dh- JSv9ŗ?ۆvBuJt~NMDv_lBAS3Bge* 9ONۥ +nn`3D9֨9.A/uti_Նy+'ƆuFN +=.BAK4hUfƊvʕb"&q2%=7r>eea=TJ(w:Nn/\#P%^^5y~QB  Pli2^E%RCTw*gLҵL01v+"؟Xjx !_ZStK" ~h8$ye_6.Q=m%F+iC q$̆@'WY+j+ GJ4y{ʃm̈́DO0{<-rk+kUih }m(b'pl=neSR{nE&-Wc-UZ7R wp<#qJ ZWRI4TnD67VE?W)SaO=G'˷E Ps7p0@үh#>SnPz@AN9å+?.3붓26U ]I^Aμg0(J]_&>s)v> e>|nA%hTu4cy2齩h:'F&Jar/pٌ:;R +o[/ߥ2  5-l˹~j=5\JWIK-jSTjQziЃa=OŕK}Ԁ +k:ŲB맖E( O^A=4cmmS12#w:KSjkRg ),E2s}'*˄q<- sP]zjx7W~KFt$#դGmMz +S~p'/LFAndZ 1llqEs(<57%,$ub;(kjQ8vf paSkb1gw'-G5! eD:N9 2pW^x+6Yecu,!+ ĸ悪F"Ӕݲs0?±y).gQ_x6V伛Zr5ia,虶rҋ@2:AOxVc●nVfUH <'*_?).ˬ@{U6;#X;ZDHo嫬jg$"@ eݪK)"Q'4ii}l +5Iq}y]!y_xPgph{4kLH-W ey[I( +G:JUrj{S%jX Iʄms?a%2,OS;0>~GIeҎ5Ajɵ,a;jA{vS]Yv4iڴ~"it1N0ʐ_H8$vM+oGIsB9nyfp&4Ŋ#7F2ԇZu,K֠~@5aம7LMV@eFǧ.sPؔ$A&=RWVhɃ:ҺZp 9/ @`vgK}* sAS +f\;Z_5þh=2G/&ݲhܶ.AO!zTݠi){.cp4c^P(6 Ix3x#C-pEJt5ac..J/;P9VVNf:?X9.U}q'{˥4[#;v6ALtFd;k&A5>}pZʒN%zq2%ZM;?F +RhkW6`kLOL!9@AVIһGE![؍fKYWT4Ә wu VgSM)L:2YR|w\"k^ a0=.ĠZN]2RU"{ }Ue{9opLi1/G8yKm1O暫Q(5ӒM78li*-c3YI ߜvxqKqɳ߁ݸa >f8#`baC'"R#%E%[K6\xXFqSr}w̏+qh%Kg2Zl{jB1sq<^ +PipW4_aa%]K dO7Y+N>,uv3Ex0.ДOmekzqWMHx#LNN?t#ѫcZ|񘺰׋%;q|dt_Gۆ\VDR10ʫA)3j'p'< +[murv&ݠd.ОywMa\';kk<}e +V|J1Mv4RbQ8@%Jj9f%(7k(Bl!rc~e̚leK>Z +0joM""L1؋h0r>7 1B:">Dל FoOL#4Tga}:*󮐾}RF/s`^О4aP$c7|F Bwqa_768.GxQt~>A`5*zFlؾ TV2DϖºI>G!~FUO{&(:'3۟7ϭ:5AҬ;n}\E]z*\G;,mxX`C;@6 +(38Czg,(k7?n| Uˑ`*7 ~/%q'?c `Cɳ.z$ř~kiNs- xVxbZn~'_ʇ@ڐD|F"yI9ֻW/۳g;Nh[K9&6nS`Q9 +endstream endobj 63 0 obj <>stream +HdW˱\ ܻ9(Op];I ^Οb?fʿC $%8 ~ +D2/]oM Jf(8 AFlBrx  +059F@u5گ]iAmp> p%] P^qPDo*>[ Pz{q: f"A#hcFPcHC +:w{X\ :cc +uj%?E &~ ' f";}Uh0o,jdm;M/iMCM&nQ?]zK>yWSg1v X8vS*~2fʉ]֘&G<\0Zֽq~1Ts'N[.-: Fq2Nڎ:jlNe$? P9W;$4@ZdqU<[{_ +hɟhan/Rl&3HgPm5~7` +Q%FҴ>o[M*E!u:MW־5up38TIaǎ]"v)9<ƶiu:%MD>bv3@.87S/⚹3^6>A&S)v5/TJݠ7ItSp-\ K6'Ǣ2 # e>si0$O`7$^^ Vz_yWMUvDP;>M{,ū!>OrTaȃa'c&)x~zY*IDi_ -Z}x\;cZM5̙5lc bm~l=0j)PQ1q. nc]25 mpsYݮOP2%'MyΌ| |Vٔdz`d "=c#AS0]i x Nisc..r3@qxY ceu=`V(&tQ(khS,|,s̒ ޠE"ଏ,Ӧ(1rq{]E=gN+7iY1/h{Zq4&N F)#=Hj4sq;l*;)[ +#+~O9)1DT +`74gЍRjc'v߼~`ThWm rc'w7.di8*x6 ˠw-Dzp@9RF6+ ZumWDי^]x )Ϙfʁ&Δ2&Ҡ~a%0}Py'苸s)^M]|W{[]y$y\<ڗ OIYpt4ݛ:쏊0hm k]b75|i{a?'Auc]z,pB/A̻2C)nxt<&su]+{ޅ#3-pQݵv +Zi=5 ~u+;Yul?*n F|\t ߰CQ-I{qRXˆO-amL* Y"Ap,CلWtnl_(TЯ}N@G|Ş`[ܯM .eY_(@R9lMb#)[#\uF.nʵm)udɿƗ\lߥ0Rt%/heu)ia#ud/Ua_\})Ru 6vйtEk*?SVh6 "0;/2mPrYK!׭tKߥƍwvqн r}8+`sy[x~Ϝ'?n)L|; U]r\ϤݱC%BjB;DtY}s\pAtedWR!.BJI$؆<9aEFokCDX4k'+pqHӣon]Pyu?s蛴ds{ٮ.Bb“{x\o}aB^1qr>kpn P@\ۂ+?c묏?QOpʞ5sۗ)Ay;;]Y$-x {/XX) ,??:rA9tq.)eZ}´ 5l>d ;Įi䁿,} +8|9c;<bջ'gB(Cu; t _g!D+ɡmtUŭPQEW.3WޝMZN>c }E,:RE/ +`XT_E4P_("_bxWgͯɓe[ j[om1솽'NTG^9:hN9Vݝ+@"߶o0ۭ)o?1#KA[f-O}h#wTPnxZA]OeU]63܊1,%znw/9PDs+@+=__(}~p\v 3Zpx8Y.w "~.LHN4LϏbH;-h #jIq6q5B+IK+&CbOum͠u+Yк Tt?6\A&6 c lb"8Yݝ`h6,sȱ +"9u2^U<8H/hhKE\ʓ~#A|vc47}2Kos E_#!m۸0_'_X1I\-ߖ/=Q_dܘg2%AnK׭ B22^H6,wбWE^ĽԠR5κк<Ea"1N8sR5OPtb MQ9x"x~j/i7RT$*jS<,fXY I% p/aG;+sXa%ga[BPDYxD%ȼtޣbSG@UJbѓOϊY0nVZc/@(}]q뎼V7%$ +BTIs5foSG/ i*-Nݹg#Lm?8AsXu: &`ʣ징pB{lY|;;xWƴmʡe zfEP#0ـ)XCj; bO +62Z\m'cɵr6.o 2R:2 a3 7Li[tp3  +oAFL5x_!J,d~|_'R+i0Ȧ>NN:o[`#~9:wPxd:WBAAs~(\JLt,⩃[;Mp1`ͬڑӬs@MWvٱpzd݇{k^o}yE,n'K?Z.۰L{w!;_r݇6!h|ana V2^WAM-tt8/wģh; ݻyo9<45;ab6,7VY&="xys"lzT^YR9#.~|I(b/7';8V[匽=liDgq>h3/gBfZF``2z߃dëo;{]m(b?~]?}S⣭cP*0a, N&Ww xD#9"dlJyp%[ۂ63\g8(^3vٴMJa.%rNP=q˝ưRx{v݂:Ryv]Oeu{|Gpk(ݍ%弍6g կ܇@[3]Ue`n֒~VdLOGVUcZ@k>͞6:$6Nqڃ ]" ̌-#;Nl{oWp^W&^j/ ӅN>޳RfI][ؖR>l28\]A :D,▻fQudB󦮵%V0o;γ}pq#"df|1t.}Ҍr~ƪ[7V\f>͐RmlR||""IAuhäW.&3ޗL((?ƠSsȢrY^8Wܫ \g]\iQ(  ]s ܠ`QזvٓZ+W9J{!>^NuM4ݞ|T'S.U89DX 2£m_yGN7ˣ4^=rz +.Oi16NonrAez/9waRg0Ef#WcHvu5sHXiWD?dNN+򆇔.ZlVKV! &@"_[ೊnQXY%c7jT᪥BX)DŽtl9iVc7 +оȥd=vQ`}x%}X?2*f8#J0͌~"Pin>>)NCG8?rbE5 j3v'N|ԌO'RYT{/HH<4ٴApZ&poZ$+uM$ 7۴Fp>y&^YkS!qh#1brtsu5֚$,+qʖolN殻47Ĭ-޾p#7 +Gs=H[elZڳ8-[d_޽A)uo{=&rk8j>jE\lB JF/ϤxTHtv`#`=K.|2b~D 0ISwPi}s BN&$ZW23 aVqŸ^L\x憛 +"J&tSdL ($5jftHbLCz1lj3pBt9n3'olVHc N=SQ:R8UkkykxtqlU[1劣\M^Iwa1RrF-Tʼnr^>nwGm ]~H"l6.IG|}iE"t 8´_ݏSg;_^zVuc^e0$8rԈ)W[9QqylULoʹmNZiSdl̢cHxN˶cYOūn1){}_?O?}O{>_7___E[ xo_ *Np7b}S _vbO85??b67PޯRvs~"1 iׯy*,#~&Y[PuUGc @6"V |~d!QF̕fi~i4<R`_4duC/8f!ufb몎,aB2y=1lYHl +00EE1=(lC 9F;(EQlF 6l7D񰐲nE"+ [FP !{2%M#r'^+]m;g' Lw90JNIfm=@CNEUup(Onq +vE#.kP'(0'HP" dX`~?7K岓DqB_#^B]0DRSBWOERRە|%"o+Rf%_MX<=z[)t&8W|IkDN8 DAྚJuXL[ x厖ibxwP1}Q! Rȷ$ВV +%A !X{?F8[m=XcjZ<] Q4==3v>0$`r3JWf +ֿOuW+syzjX۬d&Nth~ +Y-k/Nf6pymWma|dzP3֚[5 -4 @6x=`5oCnM>ԩ)T{MVz +C0W 3 [m +98CDj<KϜCw8-=|¬RIШ6#Tn=sU +9vG#g]K",$";UwZAuǃuD 7,ʌ{ )UY' qMJ +4bgkȑѱSL79lo0]&n弎06-'}[1FK~ʎkjG`ϮS3H%sFɺ(Ln^Kvx:=^9|OPX!b%h*0VQ[CPV]N TKd0z}9p&a<ŸC+wB_Դ>Yalge4ks4~i`vU+)X16rxVݧ\}5z6z1p?FUM,?aXR +}bWg2agr֖'hw>-zIZWn~5fs̨:?DWI3A7KWyzw#d:|~w=_jxL&LsxLaZ[4F!gM5cz=q\؃As=j2>򆊂FarP3}tq5JfzU ]2s{dͼWɝ8V[;7X`#hk"\n%h@GuɬvZzWjV"8l9\p`k+g&kY[uRFG9ON.f~q^4nN Q/RrIC`ceM¸cmYw?0=q/>7 憑C~Z B'ǨCNpjU4s?n!`vT 3]kinĚ%.f%ail3d]ҕ + ~ X󑩚>mLGs +]BMCRè-Ѣym!hV=lo+: 2p7,= +osF*@KFO +HL87$.)h,§\5 |A]; q+{'BpC <Æ"yC%+@tݿ}'}ᏗW_ݿo_><8: Ż˷w˛g<}g]-w⪧Oo~ykww./?__z{/!x7/_~zǻ__DyKϯϾywz}?->rinZ _a8XIQNMV4dH+醄KgNdr<֦< +ulz.ừ*sqC#ʴ* q- $n}Vg$вVGvl뼙yEnobC^ S']]_J[Ķ6+cƜ Zwm\}4gĉ[4=HFW?^uŅ˺a"0ֽ,~SMFL|<>9kH#6x]ytDX^AMC͡m 9t8fFTT}ҶIM?<$G(^ 6AeAM߸(JB$F)h܂"wWxG1Ƴ22[35d7֥gp+XLVb[+E1ZO4>+VJ)r'V{ʸIr,FI 95b"RUg$Zi._+/Tz_W#{D([B2'8_Fo24;xj^ QviǺN3Ҙ9v׃`\ץ@\IPxvI½_zycL7ƵDiڛ)~!iqjh#:ܮYz^j8)7Q-&Gԋh@ oND'hy J/aak1v2 n|`rL95,k^5ΓR90:ٛj.竞cԔsu{tH <҂NHw2u9kSΆFV:'xm=Xk52 +iX\VE\Xz7ҾH3t@u?Ž& +<6 z CUq@/hlpSEJ%^fw 6ڔVzeNj6Og@QHE)%dԔ1t"5OH}02 .JQȌHPx _cc~F#<2T詓.рvU~)2^jf¹6k"=Es~>2zjfU!vuP)@/e_kvU?&FH!l1EQig<M{۴LRP$.e +endstream endobj 64 0 obj <>stream +HoHΏ8?6(ФEW[0({ьn4o,ى2i@++I3$$`*'v=Izn5v+S8g;( OmT]Yiw[P[.¿}p-,mP~k^;>dE^ۆ~ p|8j=;{+ѤcI͈tGJ Hi',^9<Cgpf;0{:SG'/HO#tVRlk{!bߪ4"ISRlg#Z#T`d3krB"VlC5>dsXP֜`xʘ JC$>J8†w&  ƅlP"!6M+ +DPEx x -{sg—z*iނz ff^ʙG'|,+uR2+'ԥ%U ja}ш×x'h~1s%K4`Y-D֭&eˉm9%?:!ܸPGC4+J8>oo^ƍCoB[ۚw@1ضa߬&kx5S4l)53''4ͣidgSYJ$vdSEw7/r_v__=Gv .GzBT3IMTt]WGxMmtVRlEXA[^jq.|YJ'ۧcԆPtl]`e/";? rhS>黫Ta7Kɫ Vҗmk5͌ [Q,evJd4) +g,΃[-a]{!B-&z!셰—"J?au6y`/O~^{e)(o{5otVRlse5sg}mm7V_[?G%Wg),dƩc xÅ̿@&4ubn֑NL YgHAkzBus8aAY:\`#Y geF5I9qxz$ΞZ24/2 +nJ lÅ TGIsDVM.H\$BAöݸxC^)⚦XCmzp1MJ.Kx;օIhߔmLo8URWBsS{q"AI+YsF.Jͱ|m/V\BOvU;έ(2!!E>;Rj])G: F`3΃Y@vz!Jz1E[DNYwD :#zߕv^O̮5ca[3bߔqЏ(W_]jQ~Sp@*` +`2|=}wQހ*/2ޓ?1ll=6\ $nbNQ'lx넔}Kw Y㴡:0儥MSNÂ[l,ٰ2fUpp8Ըz$ΞT2[}7#$W"v+MƦ$rhpYan\!HqMSd@o= "@LJ.LJ@`фy]phF6SU,~ !4y?W1[aW,TM=k4Y) b ΅/K)hV_Tf/+At\}gFNhw\kP\\,]031v~: ga.$L-'.|6 |p,&5[T +C5W뒒NX<\C<iakΦN'x460ڍgܺŌ@àcS04 +B:6V]5w\W!Z:TpSJ.\ho?j^em2=_OMlxߏoAfaԘnIm.`n3"L͚{gFWOǽDv}j M$Rm͕B]uIQj',Mk.!n Jݚ), MʘJT.xax Jq`F;6V]5wW- ܔ M&C7Jk-lpAR&7 *tx4NZl փ/>aM.Kx;#CXl몋@79W|wKB +X'#;kmcE +2P͡d ֪`*6z̶kmdό b) %1檉rPcJh[he7ңLVؤ؄`V3m+A62O1m1:&w@tG,%~Ngs+L^\V}R&,t!v}3ՑfLu?nqJC&b|Bь12lg= r`8B6>|1iO]͖"5WMHx3N nu%4[Nݷ<o8UR)c|vx̰ ҥSXI9܁΅/K)F hElf6\G Zhɲܦn,2XjpBRNd8@af62^no_&`Е2iih2"rjŴ$z/\+Ʈ_C| !! ZΆvB@A;bz +kK?w L5M@Hgr|I 6X; ,p?dS#Xi) bw\lXu{.-E2NF1Z\tEM6ƂȩӒxW.ߡ1Μ={ ePyX}^Uଠ< :8+2˜6 +ht#$ dt'cdt"2:תұXe@dH/eAi'c4`^_ZHB Д ½LnWi\4鴐. YWJKM8'~U¢4|L"Y6E KS* YS\P:SXQk)| # +)}*uz$aiE\8hfs1[*-sc3VC"Oxė z'Po2V.P𗏪 ko>)VyvGaxwzspx_2XuL4}:q` :8+f2.sxsƻ6uG>~xNŠoc; ~㨰A\`fq TQtt.?mSYWwoU%c?_,>!m<\ffN;P`^_SHb۝Gs!r[X64.S4gөtbEf=2$ܟm=E 0cw! +endstream endobj 65 0 obj <>stream +HWko۸ _ +@)<6A/fQwY,.EcmeɫG_TvTTۄktg̙.:b$OO+z{me2IQ)swyY_ZO3|d8k/iVvs9cv{kgP70iRE5|e[C[h_pgLOz/$sPhZM|;V4,2lМJ;i=P]眃TdEir]YQYYmݼ}}4袌{2~v:*$Mn8Ϛi!MAYdy/P0گMG2ձ-zY⦪8k3}<[#Q mdqD링{1WCRv$~)'tOLЃȊy'_ޢvIZ_^nv>mLvw(d89ר+t]WxT\jVvmZ1e\w{ܽe/JkJ?J꘏Ԏ\ b&E^q⒣-WV2fŤAßo3rp}7 N0r[SDeVquMt eZOM3^H3!fsѕܻemz܋M@Z+/J{YSr&S4Turz1u';Oz +'1.㤎EZIc,â) +eۧI#ǜ<8p'q%F"vR/~ YiN4,Rkt&@12ܽA:+Nw*<ˌxfԷ_rNDz+y +F'aX4e"a.MҤTqY csKCo{Jb&˸.JspMIIy/ eO-P",Pڙ)l jq`@>- ?j_ه"vaf}O^v־^Oϋ βW\hw{ ӫf?N1c<@0CS_`ӯ`"ʆ0Bj>k?]!ޣNqq{Kx4"AQ.MG"!7(o}0ʩQ5R$(p~ؓqHB&QD ?p?SbpDf@ 8Z1cAx +=  =N vayi" C>ﳐLX1F=X2X>+\7QI) "srP/*q(9&I3XԱ2~q{C(oCyEDCV B1 1'ꐜ`< #s +c$H@%x}tVpsF8 Hർ`74P +;'A^ +tqWQXQJkA}@wJ9CA0}4KYYc}HyCa$ " Q uQD4/T0Lt:8u`L ҥW(UV+ԊSA4Pz! + #}%N~2@*2M>7xQ+'M>SC V,ODBA ׀H_ֱV\#T~rx$K^cYH 0 +ϠFZ +M+tgۇGBU *a"h P7 ׂؖH@1E4CGЋX +lf״U9> %B-4.C e&zRi8*Ԍ$!gN.HpCG ^4[~8&$P )VMf,gw"Mu= r %Ĺ<0jNE*fm7~a_( +A@ !@E꙽fI_e:yknbsH )"-`LKNu(/WIp{7ځj}Gkj7&+^F [sj۾O9Yr&YhFSp`"UjAm쵵|$wl(EBiL3K4QÓk)VP#Knu0V(5Y{~6 K=BEM3zp5H&? yF24mf R #f XwuҒgu~@qX#6byy9_w7h ҋO77m^6oS7zI>۟Xst[mipYyvDvVO wlO~sK~n6/znwwyӻw?ol=9 ddcVv~2F'm;^liW-rt(Umpk 4$/: h_C5Lyb*j@$"R#a¬ +ټ>ZFLyMW 6Gjl?,Z/pF7w>ݏ?3lh0y#'; "3: 6Ю)}-- ڞO~ Y+6xr+Ս8mdȹD[p5hDK/}pU2, +i'TheYL=7+\iv  +\`nN`ۏc ;bϝhr`͚ +&A` 3XZ`+D]Nw|+p!6B;x/޸ +8C~y +hEܠ"mP+K sFhb7E!k8{sH.Ԉ4®h)B )z8_Szz(!bٛY1[1|=nR@=kB߯F0d$n36wJ +O`SJLVfHLbgՅ p3npfC-:t+Cs; +n95A\M&3eeniTv6؇uC}_l<Ĕl`<8q3UFUj)SO9gYT UzGJ3NSCu'GOƊF;1 !}lδʛ,9j)P=ЇFmTF<͈7n٢$챺,YݠOl5{z8'26 'ُ*;2}NӍam n'Qjgd'(ypr%h5rqfgsDX*V; 1EJ'iuӄÏ_3˦?F^aG,dczt}yz|4[58`*?dfѭZ0d+JN}n=Pzj?l([fL5kTkeyf|pGG |T3[u:ZIhC{C0H^WiR:P&/NI(T)z0:,#g"zt%SJ {HJxPi:+& U:yzwd>d%aҾZ3AC]0!jB;yk $ř"*`'C}-D DT(=Vޕ(,Y-lMٽJbU2YA0r1`xXY&5BGe=":TJ<ӃhZp:ZZ|Rg:29b#CiAR@:,a]QҒ r Xrkطf: V$,v;ts;$c2PӖIuMIj-ʹ4TvSESM}sX:hTʚ*ޠ)ȊuLˈ` +A~ mFJ`$,Sce@umXbED]!bjֶ-NV P٭GMtfݪ& TppRi(D`}L? QK@@c` Cx+nT:@iNj?n7FHy "|$=H@!ICޟ1:&*"d;yk HU*]| %h/%ZW2~. +.J3݉kJ;'-:6X+}`peZŸvq5Tw1rwS>ϹSJ`T|d#w/7Mu0g/ߴ[rv`Q1IG3|#ܨOOլrvNu֍U $DdpdaI<.2a#86]mBYGnyRA+^Vz㷘8W~ͧO?na8?~l%[+cOcTn(*V(2M5r>!q@2 v SCrDtA쫨]kmt-1WV: +5>sc@Z} &+v džPP=NPBRu(I1Y#N;DlRA>$S1WsqvN@IWs_Wɯ4@nٜmpxFilǷ<ό띿e0 ݧgL~,E缶yb{rT +Hv ӅM5NГP Wo~p+gk_~1H \]ԉs(khrPMty^2tt$6TB"QQxW$f9aeV?q3}CpAFq튭vmR^f}lY%@ޒQ,Ha(ķ*5|e[o-LN/onjwXh6ʻ+k ZJMUkLPpZ}@0= +  ;'Gqϣm}k(Sf]wKŠ"^b Ò(8,ya*td,ĮYO+ھZptr6UkyVH4>t43ejcg$yu*G0&kF|+A,U%7c4eWXxTtE+,Ls{lrz0;Z9@ň~36?&6ޮPYC+=4,'Z1' +D=#Ud*B\]{_uJ+OO\E2?5t)k|9t Q _v _.+}F֚^pF_!E:Z*Q#Rч+4y/ +prvt6\OTmo +x5Ӽ[ڣAc%^V6BV٥Fvs*lNiO vnjc,Be0M,DI(ͣ.,) +\MBSA1Nnϰaa +Aڸ,Mel/֯^`Ssj_1 z>-M\a2#h-Vb@w:Ȟ5- dLktA;EMA#@ɝ>T.5'_*6{mnDUP AɳICc?Y[5Yq,mŎ(@ ?y%OIA.9ҴӅp? A]ERA{3?Lߝ9sDF!(X9GQuk]+/yo :!/^.g[ȋ\N&S4kl=Ex-kLKP!',?oyc*J)?e!=Ţ6Qee8fkR!ә:(CXԀ?qdIh4p!>tf+BdokuhFqP(uPS$5ylO#\ joUWnf@+f$S"&ݢXܡ/QT/*CC'*Ĥ% =_n +CbFiv ^>1H + R9KΑƵ?(4?aQXMbSy';{_9/L~yM~;w᳼NXHNrc7'/ل4MCNtW:0x /) |vuhl&?@ZS.ƓSlD+5{?u4*ǦoGk DI 5:Q#It +ѐwۤ~Ωe"_"#it?4RqE]ˢ0cO)$A-Q H薔I|4=$jFlE\ƋhRpcy}hbV&7HṆ,3Nc@*i `8,?Ӷ2A2F?y>T {P4 XfNB:̿_k'lN@x&FzꊣFy' mp2$ZcZ5"Vbewed%“\׍t(6,+5AkR 3.)D(P y\N^w4uI>t= +>63"(S,kQNފqz]IJZ}b5[֒#i{4o/*.}CZJPd}?* +W0)m!- kQ9b_k“в$eW l2fhhn +ijڑ-nw^Y$ʐ%/JZFXNhaf 8K &Ҟ~jf'_V\!٪яUlD#21?1F.[w[W*l^i YW0_YXnldeJ*t[+!B h٭NExc[{ER@,"jZ9N-A&c֋58ظ"(jeYR\u,i +7l(:X.56R0~M7M=f}W鲅+}˾AgKIhn Qĝe>q)FaibF^cm qir {9xmp X#|F\[J9LVm}=:$(?)ԥ[X6^7J[qʜڎGY9(AJfL s Uܶ:J򙽷% dEpb9̉um cdՋhˆZ㎗6k:wi< +׃Ǧi8[*Tz}JGOY[AsPʀkɋK>nkGދN^6hރ g#ʞ7TUjvTFΕC1K ٶb\Qmӕ )]o4̰93XkjV'ikBMFRak?I‰hЫ䰉$7m m2tU.F# mTKڊzE;covm9]ΎY-I#?*:7ѿg51Y/ԓ=P+h i-5gNJքRs}_T*7a )$ +IafxS60ڂ0lN^lN%s4fhh sNuS:X>I3I>:z4HSo\A+HgŸZIT(F1Mk5\@BS)R'Xr~_Icoo߾}?OW=yyt7z䛹.)*} zW9\r(,F4)n5(S8VKu +,1)ꓽ2Fy?V35i_8jCN1h-ԫ[s/RuƐ"Y]iJvwlRԷlt{kUEJkY$8F0 'oZ#)b^&Ȗu8pI1 ]NFm:[-縒QLnlX Nܓ p4m9Gswײ "1,L#E@m1F|j4j^ܨ3mVf>ib.~ם5xhs mY}o*AiRc_7ӻXݲ[v_ܒC$O),Q8/ϗ~M)pfhq4:D8j=LYa +.eC44i;G;Ʌ9"% %r!mT-,*\fWm•\5[bm2rM q-*Wגͳ4ǧGX»ز9'>‘&ţ+RRO9Wcqtw!tBΥy( PǨLCy𖬰>stream +HAg7 #w68U% U*ѩTM|{~ǹolfq8zvz-^q{߽<>jmݙx73.v=9yZNq= v[}h&(kX6~iмa9p3b|GC~99!/zWY&ix;"sv^qfz7^~efo̻ "~IBP)΍}NN&tڽ >bx^fOȶ@ +_71/3ý=ZS3.'ein}Q%omau!H=}ϊ4g?mS6C,r} qbX(EQ4үc$S:zQ Bm4 +:ղ,1j@us]0m) ,K3.r5>߼gTiq>SeK]hx.lz`)hcYei#vyA-1U/ܫEbvO_3ï[zzo%ʲ&4>W|Gp(Hˑ kVշ/J#^T1?X7@=0 9Z6yaM)S:XS~7?BHZT"?(bCjv _Hq(:hjH9نޚPCs%AcZuq"GBNڋ?DrMETFwoDLb* +Dăwўq^Q7n$rTo~vz$?*3GF 2HK  \j-IYMxSr~w=9eKuШ#d8W< 2XhSLHzyH)?x'3k0wuaa*xV?E}+s,ӼAE)}`aҞss+tMsS`܈Bcfc1{oYy‚ QkV{|;}彭נ߫)AT=mai#~},Y%B#Ϛ~*8ejc07[ Dvv<JbbK8'*rI{itC>!~}opS +nj|1q5J{_wqRr Ղ>|SdHP(~e|V+^els=aUޗtAlL&R ARAp_mS&0|/0ʴNAE̟}A_?ç7?_~>>y]Teԥ.4㱒(Yн&mMAQVL1Jִ#9 `F)Zݩ#Sii1jU@=EiBT +Z!Y}ߚϰ}ME#ɶ'TP-Y%_a[hZq+Tsg(5㪢egCVH'\8FQ4lP6h3c_Ҁ 4>rޫt6`[ ޑZMQɏ<)#K(_ŋR^ \^'j>|OW8XE^}b09?$(C}Ρaj31a}i: +4Ehzu.,Qȡ}-K?硒F!#TZZ4!hش/vh-P< XZZR$uMDz1r4QTngD殺D +hxJNY!wq*paJRDV>E3~I굔ĕORVIFAC |RXc;jP{KZYڋ3oF lml|:hCe?=kfmrx=o#j*B,mD3Ϥ !_Lzj &jIZL G lShюD]UV hބࣵ6G`:4r#u˲,tߏx$9ICgFilaZA}ާڶq &Lu㜽N,\ʙB +lQř̜. rN]ЉW#!9݉05NEu.Wa'JTIJ5cYk˄3;IX^vɪi'!aҵsqy{{PD/9wE.J+QB3{o%9#lAbZ"=19}k;Ƙ^%(n1d ;|7'j;Qr9Eb4#Ͱ;kYPCwd#}5U|6}n.U~*ʢ2OI-l>PÊ!3r%19mEE\GR8BZ- .+I͊/m7c[r(hF4;r);JٲDJRfhT:G>= 5GdZY@VoO50/bHF:"$5ЈF(Dҭm5Q,#&r&cA"-BS!L]A9ZP9 +OS-%nj_%3pʇѼiCFl7 vE$㴱%ӗLqHk9wɗO獬|:R:f`(mf&ۡFʉUNQ :Om2#$"՚5VpD XŎq_b3Ll5&Mtv*\Q҂wQ (@>Ӊ8 +_WRe<ԠD !jīui`l64Ĉ*9)6VuÄ k3hhnOl:PǧʦZ^X8dK9J}; H`;8™F(fQoEk60K֗(I)|^€ ~nvlƌ—Nm8-I*{ #ٴ-FAj W+r pjM܎ z44ӏ@oNcӐ:%{-㑢g{ Gg&Pi)Qa_^?~Ǐͳw~su??i,^޾=|/?ܿyn~Wo^7o~wwׯxyݧoo~zQ/dznwz"|{}ym<$Q|K E33@3>ۻ|?JG:~EO_AWUPw1L'{I>[LUAW|MLC5Cjo5+IZ! sd@1_~g4HPz?>hƋ+&i>9( Nl8 zn/eB̐b,h9K WD-K2qzƴ'|:$ +H[>9X$̑&|v?s4 ܿw'ono9{45_Ϸ>C=/M*+O.(,0X,UJ+U&6g$Lq?̳R5?iw >S{q*5>Wt"Qni ~I;B^huY"@@v`Cs%ADg4;*e +m7cN|41O!R>R ZVK{)6HN_jx$DRhM[JQ Wc;/M%VX<,6Y#dnD88 Y%9-;;f/o:DӄgKx%j>ٺW^}HWk"Gu"( Vˍ$F!9Ehi/ z֑&RZr= +Bܤxita"JT "*{rV!8xP+@4b.vrn(GNjRA {>Ao(4v ~n S6ەilZLI~ z8oq UM/F*^qNG3:IϪ nriW]þ 2}N)t7>V/ 䲪?/$"TI̿PXI,dV7eZR])6y]]kM{Nbk=ӡ/󗑥NH&"Ui%\ /`yťCWI7\Zf8`8 %Ao/_4O{߻KƊ 01?l$XXΐٌM1֤ė*1l=MCmn9I]~MU\%@Kd-QNQ 2_JOxSE*IJ[nMuHEj%Jdaѡ͊Wo>m-ӐɻL: +RxȊ0z@G`_lE.uWedPACf*Prd"K-sBIr[׋$4a8UNBGڔ"y*(5Y`3(Fy풢晔MK=粲} dIelVAmu+ϥ$zvv%4<ύoJC.lڭj {м<R/8X5u(]WkC5=Qq.KX$ $?ʥkÄW#([i6*B=<߾'J#*/I̸%W?t(P5Vb7͓%5a[ِ86F&l1gǾOx3U[2[5#܂5 f̟ׅr3k•> ~boSΘ9.&X!`]&%cz Κu)aXwWK0kLQ`~USMI!vGBzhhz4[䃎ME94 pS$hZ@DID_;o$;KLʂԲ#x}GzAvN01!K~lqaNr^!j|@wMPA!K {Oh(FϠEP/ wqoM}-@6]'8v \PN)hJCKR\Zsp0ޏ,@$۪gU U)KK|)xƳ !"zfƷoKi-ws[L a# +Zt Թڪ B\t(Upсѩ*)cyJ# m؛M8c*=1 5D Ε˘= s﹜$up*uϹ+R`˳$)mvCR2Z}A$D?/g=+}FK-Au̇`Ykg)G.̹!!QPkH#F#C~uZ>H,z_+q_ch$䩨W˅ڗQ| +!| φ|%Sy>U!$p}DڹU`VO)8e,ef0@]܃ +j +jOQ d[g#ȢM0G,Win$؝WZp$W)1Zҹl;KN]zF~P%q;iw8a`im"5ko4z$cC}Hry?h!_4ی^[sG ĆOɗ]7D۬(,⼴9(# pmeM|(\n}Ba&p5*W *X[aLpnZ,ە,!y>?j3b(tu{ʕz$S2 )؄r.P׷&q/c:ň?El+;W[s=g>bY:l0>Wz4J;K"q< K")E Sa+ŀM@ٻA\Tho :5K!*>KMLRbݲEbx~p6$5ug'sB'2%x&-;X*E-X6lwH,!׀,CU%cM㧗ʉѻ+yb>'V@NE=PF"5cNuTC`hş3ґx\7U~LZ:Wif + Ԏȩ/JMB[T}*b\HC Hɵ(t? +~>QxyGYK/9~2 خP(Q%m64 k] OVE@XڞA"˱йfqo_f޲)iXC@y[:ư!\5D"<\hD"#g/elILDQLOhLe0Xs2Trw隷xXUWܨEVVϮ GK\W&k8cM't[&?y~?@ŕeKYA(ty3FI ꡉoqaD3Pq5;_Ds9В8{iL"fMathh%rĸksx% +Q)\_W}MmsN9sj+0* ό6>-FEBKf@$T&3:n~"52T_|H@y8}Hrs}~lTWyUiiGi0HIy%؃$OR&=vqBSSsYFppqyh=@-9OY+^i&h][lQZ9LCȠ[Myx3?I Wb>DR3Xkr.GD(㊒ -[SBfN>ugAO{ʁlfZݾVr'Bԙz0HI j_d# +sc*|r?ʒ϶ +ceFY)-Cps[#P*Pg,!U۳3encJ5EhQ9"aAjzJڵy-^ຢMNJ[|#bҢ.FZLKF~UaoݦPdGJ?wsXr +F*ny{.FK#ǘr*e7u@7rjWE,@&Qi>iыg8zZt#o}BCaLۛp9چz,gz9Sk?SJvv h+}ƦƘM-^@u3Gp-9a-CIkHgI'& gUD ye*)#iv4V?o[rS`{rHzS[itgpx5F_4%X+i[F>D0lUVj.BTZTL~T0@%{.ow +L..7M[ø.XӮV:%8' 98vE$"g%% Bظ\N:ҵũ׀VD\*@jN۬'K  +\V=)uiS67c[ O.%@t:7?<2\8"4lY 9#ǐ^qf\&yu< G6V7}*[1!":N1juJwNz4iM + .^&&_sH`hÆ]99LpZ Fmfء2pTnŴGuL(4@4&͊1O|ꋼC*GdB-iJ٨ym9Mit9wF _,v0c4Nf"y$l  + +1\{0{IO/VZ7܊ZpOWД_0&$mI Il%`/J'.BA R_R[•N{<]ZH՟ӛ)4 阞Vz SPRXVrӖId+- V}\y UJ GQ8B!yČJ1q4U)F.=4+өj;B +;j.I?fVk9k;b32/ߤ<_u %*;ށo8Ԥ}Pi) ﷠:>b\L"WZD?,2 2ۣgO1S?_~ #j 5-r,p„$fHYFpg4DtgA}b61Py ![h,TɚXY,^BnT˦lFET$Q" #Y5֫ҵ\]#Kj=D~av9QIdG:b]rs[Gp߂ +9 u2?N[2 VXŝrPWK 9 u;ۦ,'_bAbQ+dUG5U𙀣ص͜áƲw}ΟAĈlj%C]Y;r:t-tgDzPk\{5--DzC3YCsسK ?W:jo6?k -7F'{/'34"KP8/V5EiJ "d2y^C@# D9!M;O tZMŽ<'L-Nus"$璩1~nNZ,O\s;9_"{Hᓭ4nVJdpTgX2u{9o4sðH!p2M$-;xq|P%\yuه\k5[5].EZ#WcPYK+4`N)$X5[a!SiQ!Z#m\k2q05j[b`=NJ=S`B]fԉO0M Is[}:?U'Z.!Q!4 cR!2VJW},G?\AUso/NjԑND9n?4W-^lm>p\K555*}7@ʄR +]eDK9w.=-HDjyzÏѝ6J/ar.&#i((.e@>RfVDFq[u .I681lRRZ*>B }(; 6>E8mh\8[еQ4Cjӽ2ѽ%ԃE)iz&ea&wiu5EX.Cokߴ2=j mXU#YLjW = + )!x{hwT%Y|,/ \Jez14b%V4S+nhEhlXUB}N]K a©1N<É1LBc2XupvT*5GWs]UⰘq&nCK uRcs8GRdZ\8(nUl?.'+~!"xwQzhIe +6ѧm^k]{F1G&LjdSLMw;8v +w`!6K %1/.Qlm@],tB[~`OqZ)Fb0zJA)S,[m2q7) U!d +a#A!9S8ObyԓZ_>Wyijk=6jl w +BЙ>)r@e w0K ^WN28`R"I4ZMcݐAoi葱Đr\ȴcQfaA3݁ebvMqrkEi"UzXP.P0HXԉ3Pj>ُt,m%y]g3>Y[jiN (dB xpe/.z۸Y&heolG&%5RU)uM)UӠ(xGqŊ=>R10k@M"\_$F .fO-vV%Ekf*/I$kpxU"ͤ(`tɂBWA3',vfbh#;t5W)RI7ePNJꄁb%I'B( o7̝ʌ."*@z:f61wLJOt\+ hXWg T?־cMqg7+>Ec 9AHU0~v>s* q#9x8}~)%IZo;`YKsHXv]Ͼ>~)Ҏb?QNyQ(0E,n0Zw=Ho+"1* Zۏ/wo>nPf[Bp\Jٶ 2R&򉒦k]tqMQxͿQotަU-Gʐ eE1W^SApZ硕.جwm-Y㾜V|o*f6RT)QN E ,N%6{/>+,b4VQ+KNNjN.{*U;*BKT9f%!F H(bZڷ4)nΩ>55ze %L$IlRncGmHb>;חj0zkS *$:AՋQMSGcCB@,AۭbeJXiƊY2?KA[:|\PMKN\A깖Y=DDۑ*(j*ڵ-¾ZVd!pر Z=_*Ͻ m_%+RЇ&M1ޤk%BNÍ{h3G@1=~bP@j /(w~vVc6]w)5&o8w1躱]u%^7iJ긏`Ttrã; W?bhpZ6LkbVVXZ,t?P)-vNp"}@J/^aRhT'EnL[j9~{'Իi(:HYEvtBI&SL$Apgm"f;oܷ +M̎Hh(kJxFqN-*|tGQ:j{4&Eђ/zDStItO*kAdn*^#"}mKehFsR?0ӥؗ(9^Ω$ʜT'\82Eh_g2خڪ5 '4m[`Cǥv]&`oaÆmf>\<: R*C"Kń=j}^bj +rYqjRU=#s8@3<2[U\E@3 ]aR:'Rhf?ObǘLBG֜>RŸb^qDn^V[O8#0mQ}q['KKOCtL:ڣMزF.GQgA6:LKEM@zѴcj{7\e)h+UV!btsq%QP25~~{)uQUIf]T㈛IмB`d1@ZK-f~M-j6گ94kd;4eg +9byoE=oRq@"ן_\g y&ZOW{h +;qwJ`_T^-2pȇ+eYܑXS~,U",e^ՠmx䇀uⳲ5EmVny? 3 j D)1Jɏ<(Q{j˦E ')yJEP󔧷0ԋ@qȗocTS#4 ,uNI`b5-OdcT_ݣE V3%1,V3u]S_+9Qլ>qPaI~W'F%yR +۫g@đyEWYIgƥv~k}7R-nu +Z)ŭ6'2)6RS ;e`bs)=)&`(o@dQfS5JpuթFa~O `(S:.I荫2@=d#M_ Չ/[io3%'HBϑJ>'ָ$Y66%[pF*19/Q!Y4|AH4d+*Uƺxm뛲:~rjJm+C@7l A C5/vlkUw-r2 "KL߸#bW;{.;p4,9^pT5473G*U^jtHT44[OzRLb3R%xaCFݰJdy|N+JUPjq'9?j g>R\Lfy)qLy g҅SlL]/K3YK VR7 6y-7d~ޭ-8uH00) +hsB$/h\ fg=-^:e ygf\ta33>09E>_Rc<Π§N_8 ۧ_;[$8.v!rn?CaI-,LH_Y~>v{'01nuVLz=C0dNI"&F')'G5$9&+7i Zɍ +Sd6S~X%g弫+y2#|o%F}G>gN?e=DSr!T9BT4t5 ߝN~ԙu4" +Qut Gnn r!eHT"Zdž;!t2FB`t-Y>Yǡ6t+Ͼ~aqE API6o\f̥2LbA;k#VvfI^d O?D)NY9 ķ4=`2SB))vIF;#o|Ə,GiÐG7S h$_ҚWm"jD@~Ck(anIpؠ49@mm2 1 )|bDEOʥлui`u˲‡.{@,r9f2["v^HW֋`ϣpvYwc  &P!/7IP@nB-;T$P>D >*L˨s#.8qr,w0Azl_KzoHE`" $-J: hc!6]>j RhO"a \ YU!f߭m<l\/#|R쏿=4͢nYywiG,[hh +xo`<ؾM.Kbڃ50R- m~Q)y?UZ6I_$ȽqA'YwuČtj + s<+?$[w觋fS\dbZ,$c׻\MRVv;Z7S}ya)n(8ʲrZ] #Q.J-%zJBRU #/pB3:ɳo\3sgi%B;DKSfmtL0\|Eu\u,I yky|iFA3UjKq~280;7>ͶkEw ]:Pۧ} }6cƩU=b壽 XD3wy( Xw?`S X_(̅Bوl7u;گyf'&HPY|,ˡ9CC/89eKςM]=0Q#=`"}+ ꭬φHe oDi ~^m`]6 ID4mnPs;\)}~SQw*%84D,Ş{/[֚vI}O\^gY+u^}Qzif^u{&6p r*͵/~ilD%o\A3u[רh]Ԍ/9&U0^hcFOϩen$[kE8G}~9Q_NIR**qHPƓ:RvH-aN% +:ٸ@>xCs${ԲQ/EZ~{5a +2wl6leۣZ7b.%9Ig~pMY1'2H+:EBOqz 81fmzҋ"j>?hvV1: G+S8 mJ&m,up1X/{.p Wb#Hgz#ב_isZ,y . pu"Z.9 }VHom.8|J}&td%2U-CXswyicpr~R +8Q1ON!NBpphP<{*+b͝%n7<4hx l;rE>0uf@'ASD׮ѣ8 5qmT'-]lĮ&&_h$XLI< 9{j:RkQ>A@%> _%^4r%#xdY rqEOYŵH'>y+Or"._.֡jKA$:4E2S6c24pjg6mҵYw dRS_נf"yBL!}Ŝ[pF[Bn.B?}b~n!^#w56 x$fMXCk~B2AM5WZK~ RԚ=R]Ԅh7qZQdzHT-6ո5% '~qJ|_!.tPcsVmѻSp] J$7wv$9TVbfUR d3Mh#YdAn`S#`qj@ֺTΦ!E +!l̀O~5G] >v`0&Hk/U9%Hnfwh蜁!]َS hH2gOzۮ4 wiNLPr (TETO5L_SA c;%2R!ŷg\.2E J4ON)[Y:G|:yI)b۵N>)Tia^Rڸ|ɮ{-uhpGť" ekޭ/$ +64,I0T߳/ɕ$r3uBV+ >uhR8٥[F"8(F~`rQfy*iY(u Gqf\2kwmdu1(F0҈$ц.s@(sdN͛I]zdRB ĐqE3~sۄ̺i+lg&;аԉHh5AgR +3 pʅ{=zv##+2\V\cױ-|js؅"/*`{]x tɲ5IMz5kAٍNػ{Q*ŇV2"Ժ5X)0[YIJ=[,Gu r3%m:^UfeC!Hv=vG Fa(EȡXm=jr|6!!Rw؟!߽÷׆7 jy ޡT7HQ2U&ÕD/&Z+kX7n*NKԾnv8Y59j}v {U5&Кh@mj!crŸ..U L*{G;"\j D@^|JtFӎ7m429rDbա[1@Жh͙vViT;i~AlN=AZʩȄo!z($4SU<]~5*q1oLoi>U:$)4{$_p_h #@#okZ .XǼ>\ W~{kM(p"OB4(3m Vq;>aN-}߯5ux=5„#6ԟX^l_ڰ(guY}iiZbML"%1a+1w[[{# +I2-{T$MHh:dI u>f<3drzCW5?6V3e[Ne.ms +xhQHJZkQ}MʱK-+ՄuªН֒:j:RB8֔G0k/gG&S &]|8K_U ..KJYCfH" +%{s*-hd*=1$zbR23! +x÷v ͩ%8æW,}SzD_v{XvZ܎Bi7V̤X{$EN4;!RCvBŒعy; 2:_=:F{7&B +-R k7 l`5O +endstream endobj 67 0 obj <>stream +HWMo] w!9Lr +`A \%@=s_8nڍKsO~ww>ܜ?<_}z?+ߞ}{=ߜ_?>|xx/O팇wg_뛵Hvῷ|}?/~~㺯mOn9矮d'{XvҾwͱ}Mw uNkkSjҷ033N:l1{o]v -1;2gpvm{έzmkC`OӰ]tه5e{Kht61W9mktz紲O_I:q-b"xH{Sёu7g'*@p#7xS7"ù76AN?.dYqFPN`eȑ8֑XGp Iߎy-C F)DZ ѦIm +٩JT\T fQt 8tj!Tfre^׮nSy!>֬=ӬA=W\0R6_lG,*#ֽI+KY6$^p {&~A셢_._ L^.8&'~f 4$t0 X{oj}x9#'U\P`P7!72XqҢvr"+ށś{&wK rb+H +N^2^D +MCQNAfz)<C]OwtAO >ĕ9V[LA`*2XۆڂA u?gL4X)i #xG R +3L9<4xFo8mF`7ew FRC"-PdXXOģ @nFbГVq2V';@%/ *CaZ;:%M:+ĥ$R`umA(n|rշ2h4RY +:kW(En{j5yHE@|xZĐH_TkC.j[в1ؓHMY%b08 8 +j1xJvQWjbeG=c#z`5{ @Hy2#va̩py]NdV+C'g:k(B9c6ʭ}Iy':1FBZMI +V Bp"k*a(fFMUTaNG/٨P|M6+T!/͐ åäv +zyCL={f;7ڟgCFA"G+iڐHnmm{S\ aFR|L_cXbuX ƕTG$laa azsOyr)$V/S3AA}׳MAĬYf2Xz~hx|kLEcoz  (EZ=jI\wU]rFay< ^n,(df(;C)bc":\B?¸QV V_s'rw͔<@1n{%p \)5VG;sBg ߜ1qcnera $c]%=Ҙ9Gܣyၑk7e^x{LJ$|hHø+.mdsE60Zm~MM1 `m.&H +͜ 2Wgo/Ty̾)4'Ө B1C7L|ޘ +xZ4cR-eQԾt(WKn RVKtʈs a]Eg +L~1vtRtU؎ q%LsudۚU0u[C]p0}Y %N0|1Djϱ$Bbc'{1e}uϮd?d?uF^YoK!̽h\%Wc<^OSʜ_g]Ҏ6aBZJP 5ƳB!>&'ȧ/$<EȏR)Y(كhl̃"rk`UvFKpRgM2{K]'O3tVigëb|z eڸ2Rz6-%G8)Řt.D.,VYQ@~ّewZ%GS~[ -Pfg/ e(RN'ȧyP %DRNr%7’]&+f5Q=/qϥق2R:( v- :o ^>&7""] B]JБW Ωή+i!{y(ˬD+UaB}!P°: 3 !#"l 2ڐ++P?}=ٻe^j +ܨzߡY\VG~ͻ"i +VFzFzt-JPDÉ8zx@YI%Aya[3d`SY>|n\cFFG wڸJ z&Ar<\'[AlS˜5YפT̪VSYi[5:m/X E6e,* ǵQkqSwZu9/ܞbc̨+RG3Bp:+`YXB2 Ѹ*l rGCʘ.l]13sa\Fʮ, s* z*L=GٮyB]Oa \qAM>׽J;]rl9KUw6RoQ8ԯSm:hj={We + +7 t^d:0l`U!䤃O&6oޠ1m+*'-LqH".HVP/%FUq_{TXLhyIɃYܦ?-f֜VF$_YD¨,LImnzx]SH ~KbgM,V%;6Dvz4w+&v*2-kFvEueϤ镤 *p^@"9ʼn{!w/6{o&>wo-9kn>pD2XgƲTIFgx.Ktpdw:䣚ۺe>_&U{w[by!dn{oXLΖG;)v!s[,8Kt:y{з/qw̸/ĊẝT%X+{?^]TqPqI[l46]dF05:MZ;4$ I1:Ƞ4r nW%HHKBÍCڞSB|WYrcL$ȚpLL{-0\E*PG6 +]T,E6~ׯ_NyO|2_g!坻OUe~TRI& AL'i)4k%S; -l X\ћNVjR{IWֵ̱6ߑB=OCejՐ`޻>5g^*2@ci{RG?k[[;2fჅ> >ujeu$ 1jrW1^L$9kwu$AH7r7D q"N".%C+G>-̩:~PBlb)͛ՓCE1qSY@\ԝ*g&>Uf' d{9Ѐ&TpXC~]i J3%/mClq2AU[e!SѩMC2-tyBY/\\e* X૔KVÏQ gGVl %/1 D)u +:bX䃿pk@eS,pNde׌i9ĘMAɤ(A15^Pƺ> +gGRa;(C!["Y2 V'PIU]K1z/"{ +Gm0Kb!!AV N֮Zѣkg!+#.?@m]o&R6p"4FB/D[cQ9c:)^[}d9e۶@OUL:Dbcf{c" V]]=rTZT'uN(ͭ(@̝Cݎ:hNyHI j<ݒ4t:V; +ytrYy$Hu$# M s@ȃ}v/lmuk_E>)|xG![T;@+)#O;gS"`:88`[ v[U*,k3"෮ +[Á)9?Kkx\s H :X Zהyuw=N U6~CpL"A9%D6huAvI,AW-6)0'S-& }zjf̝2Kƨ 3$%OMo ;[Ҕ2}(Yy2R4J 9cšTKL0i^3k,A=eE*88`_P7usadtmAHSfZ@Wd"*K +4ZB[!O-f~4Q9tMJ<6~4 C)PNEꐢtu7yjs,B qaE~DV +`$,`L/;h <ۖ4|[Z`.A=Z)E!wcso +T.Y].}-չE(eF +I N 5Mg%o׋XEqPqуcڈy،V.{kE^|-R7\uU)*mhg)H2o+9ifDEԗJ%# XKv!JÏJA:i?ӈf+k/itkdžIshm,8L|iϻ[[h\ہ (6OY + +&UJ +:wϭ+6gl?҆=ʌ X\S!U?,mDG;\9QIW*Bӟe-ocwf](6R{O;+XڽZa d;ڐ@ G޲YUr}wQ5xߪd: +;oU~=Q,}QÞy~jc=Zդzbr0@5A$ |vX?D<Ϭ[*`]ńq +Xoa'@ONMP5 &;E q Ĉ/ +VAIkm;"п3%K "mXAҒV=LA .A\.=CK%$ARBndpVVi\~9t!G1Jܵ4dd8#0%U]|Wa*ek(ixj%!GouX= 4b;dG +%7ԅ" ՠtjyýo>)K(n8}H^3P]|UQX6qZ<[Mw鳗c,m]ב25Jnbŝhيً4a(:Ȼ*CnHuh4S9BR'5(;Z 9 z4s51{]Yh{:SZQ" +n5bŽ#H8k%m|2.B("!$-\z /U j1 X49׏ʉPa-.N" Du|d P$!Lr ήg᪕ƋNL ,R1%Ohe3S>bC,9a.ЋK\P*@Zq(YejGr@p6 ,MoV+ ^`c<;3\A@h~{Y} x3-ʌb]CDpn ,<^i]]rjᥝqV_65E{¥ύJC]/+{]5ͦr[4K΢f# 뒄/֢d 7ʙG-t$'e G*Tegrm/k>ͱY]liR,%z݄/(Nz5 PꪞkuK#pZY##ʭhWO\h ^haِy8^1Y:NuA+BBU<)MݐqDR3ȨD>- <-rk:8ψ)ύ2oB.>J%MffU-eӟ@ =[nb}ax֊- hIT}Hl[-m׸w,%Iնgz J]̬\=tDiT8ҍ(z1Sۃ=ݚXY awe?[0U5Tv/gCF|l:WGEY DY44UVTC[wwqN>T}4/}]%*bj3g^&w w%ǖ +vc Guc?doEMErEW=WGZ!Eæg~+2ș%sCK,qPn൥/Rl&`?IՕDVͧ(b.aMܛ5Uz#F{7%Q;SRēM}X(g=Ŭ%6qy\EaR @8>&@"!|_ᩣΌɟf!ZQLHPYq1oԎ-AhdR4 +x_+6iiT HjrO훿}?}~뗟Q?~ox㏟^^~_^??x?mD5~"zK*+TȚŷ=d{Jh< 4E+x1Re2!͏!Bky^<.M8fK}h6G2ZJiM=sJRC%M5g i%7i.+pR%'IIљY9D1PRg?~Ṟ+=pHOLKGDlÐ$Jiu5]&{n*Zӣi&|]f2oθG оG Mj.w|¿ފ1Y)/wF9_ &mZ?diE?FSݎ(kJV0R/ꦸB3Hf'>p|PYX6z2Uy) +}X%#EXKr\/̅bB0š]4vz @3`;kN}-U]pv Ύ\Pؿ }lДD(HD +|,UH5b]o +@t.)a2iV2oL,GY@xc^zreU#&1yʉ6 >"eGFc]OQNG(]_[[2]Hm2TV5g-?xY7ј ZjL^Zs +M)^MY):6KFZa^tlhUsZ:+Kn|÷#)Q9f2Jiy/PUGi@FE!G[Ao:E"[gI'i~f i4Oӣɇ'+Tm ^9T{x.q)@Rz/# +w G$F!;3,dL6{N=Dܡ'WUFz8MH6Ӎ!-.6A 2XY'g5kvqO*@qX-M1DeHjP>jFS ѻbɳctZ)[BvOX¨8vE;Sw01 m$CJ*X36\:gHZ.az?׎|_7!YWWD.$ϯ(Bxˉ{usKI8ۧO7B*8 R08A& -92ygHxIA[֥۴:(yjؠ&C 7smm3GfGltnv5I"ͶmBrU"ߛ hЙInW- mUk::W%b_Ko0ՎŸ՗+QIb+4\>S*] ,J!DrY x=i8~=lmpFy\|`VYe wo]A֪:YXs=BLҴ6 êeJߠ +ֹ 0d=^zJK4$. +rW]ȲHiI}/z*S˿E{'+cmJ)RV<@vuwL#(zh!'Ė4Bik;m&Imɶ66ƴf'gb!zoZhdSYQ&kt;mbj8 "P NNpei~##V;Q*v*ʖ,0-QJj+lJ6 i!ʙT6gӕ)Te Xkivס5ڂdYJ +HےEH"׊*y2Ր0~knȾX2b/4Qi@ZK:TFڗC-t.Q|9$ctBIBGɀT騪DKNr[#Yʬm/nHi~RSuFr??kRw:dv` Iump8ԓo8ʌ*N+yD'S)Sӵc`lH- e1vf +7Tqf w +pJabV#q=S߮XSt0{R)%ڪh- L$y(C#Ub?E^GvYX~ 5H'3N|@*k!$sRRfRPƬ #6;$ha*08 k? BBڧVMJ$$6HVA܆,bqSfK3i㽑 L zT'&5/m k0h7` tdbRRĦmHS* j1a㉅uirZPuJV%NE$HjDȁX"D)^rÔh3395S٨@ \–O[_g'0:O٤Lش1T;@)HKb3ІDSF!o!&ۼ3tu6dcT\¡z)4Tc" c3\$lJ:M74yCLJf!R.3@٬(C9 +- 8z&<^ ձ"L%@CVQCTuѭXW15uXY}$-R\/|#4;)E2EQP!J/B~2iݷ5u^цuł| TJcT2U(e +~~O%*griHÉ~A%%0 ~UnY~yLfGp΄q5yy2OY4f=NkޗnL<}uO;-0&]KJ$کV7GOᚰ=~x[|Mhϭ] ~ۓ Z jaɏ~Rwc\ +S:Āւa7uǃdR;5#tyt64*Tu@`Ijjh6<:܋zD?:/p/ B3`|4+ϼ`"p{ek ^C4Btsߝ)Onh[o=3;'~tuwW+Y~8t$ԇdN2+^%R{Rm-/W-#Xf)Haof"P@ &|k4X&2nʼV50*rI0:cL؆7G 8/)sz,%D +X@"aXE>iʓ;9P&gMei4Ғ(0|(:䣖"YjAlx@hZ|r) & +W`9Cs׋EC(<~-vS>yYWܡ2$.y\ }"Y蠣wt1\~/C_CD2VL 3uΦuXYyOG>+z8R-)D/Cp3I-[Z r8VAȏU?YHq":Z5=9'}Ht-2njISC`=ݞjLEYB4:W{Z8ڕ0$\:j + 1rbJh=WȮ_HM)gr!ё#HIX.r~?hC@oJO4@.=YT”hlNnr|װiMT@'ƒ\-'8[,sVpfcJξ()reIKuo3l&!FA(ķ\:/Xi +N™%JEqQ?9Hb@5SoE_D}d-.#IijAuwU!~w_fش ^h9TW%,x тw.k:ߙoH֩WÜ)4F +."2e)bMwI9QxFTk t's:Yn=;x/B9 ɮ\>cZo<ĕQiۗ4G2 A1X?L wR |tr&+jq| k.4R(=}jAA+%|А%Ǘ߬5lpGϷ Xj0 e3ZѤHYe)ԶpuB]< ThCXKаڒ! pȤ i@h@!AszǀzCaC &j\|:+h糑_A.cCYiH@7fOoZ^iœ7UcTz71qJk%jzdWg$/cT>ҪfW ++ Cv2CVp-c%>r?A8 x4> m\7KK}{bF/mz *ڸ+P74wJ A= +9ZyYD'pX>P_xG`8mdi3/^nSz{>٬ D}zܮw[;YİSДmudl ^j >jNkX,LfiIh~Zi7bl7wUԶh.{-{rKյ{# WѲDQ(^}Koh4_ySyK Λ&1hMj/Wj[iY9j䴜CwwZd]}d5 +kMkBWO+ +=kaMc8Y4]e_vʵO;[_TvەlvfV/3 +i--Ḡ5֑jyw^}uO+@t뽾{2yh6ͧx>jOdKsK?hsVzxrx+C,%h@>.Ac6 gW4VrLYl=M6Xl(6g2hbw:>Ht "HY)u4v&o F'cvHKg$jV?%F%tcr/ެ$ -?%YзX"$4 +P-U}mx\@)nmK/_0|jbRPh2[YՖuǡSwH=&K^VYOszhRp΍ƁN+G| +cf#BH3;I)RYjz]qf_+c|`FSle+|DNV7^Ө! ؛*o 9%顈UAb!)#ԟcɑI[:<F*tzwe{wKŔqV9ZҬ)൦0]YokW uRay5@fSG,PėHZS$kֳvg(r$t.u|VӬwF_f8yP>#:B4@!#>铞Gd^n^GIjDoLn8#E-^et._|^~W/޾ƶ~_޾{o~zwW^w׷_m#o}w{sg_xՋx)9Ũ|>~^!>0l2]Zӌ'_nӛonu~./ґ.//^"w/ߜw; +펋yk`֥9gʚY=$-I/$\#._`8QV-ׁA@$$8Cї䘷98H03h`G +i`p?KG X5 bZDIS"Q3w7)tBȟt|K kIjn-Q%t||CJKg~XM +'wz@P?@!ޠR½Gt?܇Ji~l*۴HvYҙ +AJjK\׬Pw 5b$iI&,1{*`(z-W^|6]b?*+FwwÛcv+3pFj `z$Ზ'MѼ>6(Ԑ<eq2 {A*["Ӱ`J$7PBJ%wΤܢSˀ6S@w8%;PqRq^ǩIǃV$ ՗|![ +;R[ڊ+o<M:(+JBlGTvSAI*P}E҄pbPPէ'tijX}﨏@GVGURS *s- s BHmJ.9%Nɓ,@XH4/i1T6B_xz5IS.Id p!rȹQ%}b&){bBzcĞ!BrMU}V,[џ@Y}Lrۈ}5X6v⒎|VEN/hKY7/y/ QR:)0U|)JẀ1G}upyDkٚzu.FT%qEga_$u'^jyFY k;:ld+6ܕOy\@3vy;e]H EحK5~vHf֧)A*{`>Ē)07 ,21djvo|tvO.t+[I+Cd3RKGzxTxdŸP ͂N 6V0IȱJN)zJ=Pk0|QXŋnK}2}&e,=fj'FSʷ;Γo"}3O H|+懔յ-Zt,@ +%2̓yp)M^V4R^T>}J}|ыRB[޾_ yI,zt y.06k)1LM{$((ѠhxM^PQ`!M v+qՒ|xO>JًQ@ĘO|GcYDxh]{f?qw)CEY}1T(z@E9){}ʉR1\eϔ&,5Sv/<1LUs1y=J_szS +a`Dժϡ]vf aT$c̼zG4S̤MMV^ Dy3Mz`'f@C{Dpf*l[|W;9_&\IF4*gW7 +?h0"3Z[)~#=|P(%f?Sj"FP-ЗD*-'EeeSy|}6FFE0Z؃2A{teQ%yeEZ9+K;.3"U^eM=$^=tf/iH >~lAFޟIW/4J*ߑ>q_]6Y\΢ ͗N7/~|x?ݫo~xO?q?/woݯ?zÇNכ?{3_>||x?yݫX$?+?[$Y,"[Qg_USR(aR*WA0/Dy**83Dwh1?ЖkM2fЭzG)íDװA_SYZeZo=]{9O͒ Ran-COS2re)afI 񗇌\HiRW !{jE걧qr9ݡdb/:}9bv('b􄺘!Fp(a᮶CO;%p؋+J* +i袃P YovS|R3ܦtƔK[ӕ.H;tڡvwJC,[:sW3tu8i%a]2KAv |(샃A|ҐCcwxh cQT]+6ZDhdk֊/]A'ZA@ÑP +OuGPb?f}Vw cLuUIKRy⸽-P(,6+`նł\|K2ك~q}pZplF1Ȼ!yD*؆^eJY{Q|i_Ȼ8_v|@?XO|U&|&Wi;QIsG 77;xl@lF* uڼ Gfãr@{v9fyz)H#҃+Ns$~MjpYֻtCvh V^<_z0Ma#i2I}YCjFQҳۦ)&dt73ƌͥh Lu㇠HeMp7E s;Q%@L.kvp}:C@oCb*O1ujFt)p)䮊Үa Ba;}9JSym۩g;2t>e_kiCɯiI4UtT|L(Mh3zp"j u [Q$'lnkͽ YbǦta͌ںrJ <^!fagZ9l\qkL_Tu}IU+e.mIf1+dE.mojcJaBKrݙx@ݨMNwzES/yIL?F\T Z;fE(Kr-{Zlysuؽc88c_Η׮t`0+g-4eT}-śW=qq}H-H0d?_Е~ܸHzrӧoBxc>Bh3ѿ;^n_8R_=,-L5߷,>,O,\E*gNs¦JAgܬoE k2rqdE*Jw- U},8$vR(5gۚ -hw`b^~lXN|:t"UŠm;ҚߢUOߠ>˒O+k^ R_)h2 -m\8ڢ7hM`*5/,iO>>ۯ|w||@"}?ǧ_=~v_?~~㇏O;{9} Os/^t{dj}{O> 6eri>13?D<4K- ۝ Ђ{wj_q]=m*/U4Ρ-ezȧ^|Fi%-|tlr4%C%4 ;5Ǭa5jDK|Տ6g]E3QTH.&qNV!E"H+Pw aK]XS[& 0ϛu +endstream endobj 68 0 obj <>stream +HWM˝ @dFivBKiv%;`E}ϑޤ`Jo9wHG_m?{vJ|j^^CȺo2ȥ l0$nWNN2kQټf+hS+ U|N= Sg{7ջxo}x\J}^⫯^==/?G?qϟoN_&7t\x C/b)p ̿tҸ' +闳x^z.i+W7|4XipQi@Ro0bn,d_|Mp9ey޳ hpxiH*~rr=^xo]z{IJLMxvA78,KcY j2ߵ=sb] o_F"Br\0@+j j[pEzl +Id{!)Q] PRLb|dκqOdtV?O D +,AbvlA_CC:RnG0va8Lk im# !+ +ѝ\q k 5Uă' uH{@;rOZCf-GpV!m[k%žmaxK;YU.YMۓxY3ySc_|m@p ngVߦEM #QE3#|FUO}x~\d[ƚQ/ pxhU `hW5׫9>VQIqEie) +ʋU`0N46^Nm#%7:XXͲP_ ޕ c: OP],)H c0?@xc1Ÿ̙5d:m- s!yI7 + sb/Ƥ\}kAe LCw/3ZcLMXq9ЙȚLQ"IԮIшV̝l<Ǎ1 y<Bg݀8k05F`)+z0!U8 V@Q*A,lKgCs9rrR/k2ѡ@xsz9BȠr( +9$m:-.u#6V凱,/ux܇ zfڤ*E)/O[b|t#Ad>GOB^gsg3d( @l[|c3uH=qʬ,6 =vPU)UdQ t6PH7҃F>JtK(4NA-lƖCz}VԁPYϰӰX۩]>ߡ=Y+@k!'LԚ4nppܯcgk.lKȄqH4VX:!>q~L=TA7iq"u%Rr =[}\ѕxsp3B&\8Cxԙd2P7-Y S!ania.)e0:8V͌9:9 G`^3RC[ +] (adD(X65F鮒J`HUXu87bޙDB#JT߂d>6cն0{% rheZXS ?V8 Zώu=3H~r4{1֓P1i 5!ȥQ[v. "+.4=Q<Kv4C2>K+g"vXkXɠw?wB.,ø^iEPIif^| +aFO06bRɩ~1htJtdU:0գs޺Ik w 3BԝC&ts)GDXKbعI T ׾섨u1<-Q틌ÖYDٿyg,Z}Y +2l7V:=ݿЍs!nFN41- gJ)X,vM?P?fV̜yyJ7:l) %4}y`$bQh&0Gi&6`G+b\$B_iYv ̶3Ve#%i&4k7 G} ?p"8=Sl˄z~?߼Jpz6Ԏ5M)'zF0mF+4!MK  ,*E”!Ll2s 'NPy6"&gWE.BLhjBNqICnyqbC.a>g%}d T_l'1hZyڟҢ4\j E <(YKYLI7z8Ӈzoo8;y8?BMcxGk%Kf,f>Pن i24E{6s T]$)O?Tven3cƾkDPfB2JH9}+\3(~}}}"ӓ(DHߍ~R.':_!ICn凞ϫgtDzDyYb,zDFZ#Y~N?p|՟zpq{*a`ixkmPQ:ƒžIhNd IVELVE3q <;WMRHt"6FL=VDez7 2t2)o)6|ˠ$ϗUYFFC==QkBo:==mCT:P`dhM&g]rt6F(N=PQ} Oivuv aN/u3@~وaMǟ6b^h<huܿj^ωAD(/{1;%q^Ї& f@;iGR&ˑiNS)*1u]w +Auc (WƸ{ǻ=.wИh0 m8@L(ygBXv\HD= ,z?B$~.=d"AJm' dk+(-%ÑBӅT^6>ahPR^y9𯨼$H +"Hs(%̐ϫ8)r׼-r17hʊ!L(($}qk.Le'4MNa"% d`Q"(^=QN5 +V&.5M0tOXB=!]iZ ];c)h#0~OAFwڲEt=yd)@ +Qћ=@-zWmahV=-z/`VXX!ZYlWSlY@\U@ZI YUU! :UY :WQׇV*?w}L>b֥d[uPeںedlVUVЎywχQUNs%yf89LUk2 r"k檟t%Mp47L2)큂iU B9FdfBi~i\N.ԏRB:KYh5w9&%9bB/j\TBw\-q_d> kשW0LJ {_j EV?ce){)Yt4-XZDdcrsznǗ9"[A"SCf$3feuT]vkXI]`ղ J2z]ȥ:$ "˗ᖐ J"cU ,CO(e~ΰ nMbf<w;[[gq Ū}Zva餩q8@LޓZ  G5[ڝ_dH̳Y+ . 1jf"ΎWbћCVk]@?|sa8iuZ=OWvL_5kf[%7vnBF|O!1$PR/w!7ү9E}US\XzW%CcbWWZ(_,YSRK ʑ_M JZw$Da9yL7=&#hi{r e ^:.&;CPK:7aC Cvry[>mV- ^Ūx.T7u- WB<&:-/L]ANo=l]J1``<-iV$`2KEIȝNj-G$9B-E‚H?@`<cV?b'5[7CDB g9!\p8 /G -`TS P'B84KuJnHiS[}ʉlKd}~. !pQ4dpm%ה!F_c*W;=UdT=Ķj,A_"ͬ(,0Ggˮ K7HB|gLLcXpz[gb糳MT)M +[-Y],x8XjX&k4fGN 󘃹בlØawx5^FjIame>@#u)G"n8^g?$;5U}^hvTަ0׫P+;~PG3LY\텦: +h|i?1g~G[Z^r0edܠI#V#Y(g0GGW?]zVntu!wUmbfn@2<' EC=+wph@4Hg̒çqjD=XVH=̜ YQWMpi]U9wͼ@Ò8l)iwܢEBm9Vf>!A=x +"7%5㴜t\Tdc1&N@|M5>78lpqO ʵQC + piLCf3}(4iAJ` |H)ĵA2uK lg'#' c* 06_  3S"w|FX: ,̆|@mR >W&;V,, +pen/=,{ИioI5UhZT| [r!MK +iyTp=D&c162 b.H>C`tSȒ5(ݎLQ΅l#_fB F"_6>384⬇o7}ǟ??a=?|z㏏>O?ۧ?z 7댗ϟ{){8]9ǟW?>{ʏ^o?< "^?fR RHcIERHa-ot3BT7݀UUX{s ++`@6yq#>e^q"B9Qۥyx/f_"ND{h HCd@u6ƄKH0BWFf +VVƲu|@> l p?&>R}`zC7<j Wt +Huzڽ/1>@^sP9r緼 #N,LLfNg'XxK,KYti˥VCas/1BH{uW їDozH(@|{r)+3^줨E)Q5-^TkK}Q&1 ABSn8 _2 џ"8wt9 q콍U nHWMp0NDAm?[Ag!=GRO)34i\FrZÙ's!ӦhUjNXwUs<Ҹ +lkYUC8^OG3kP!94X>k;t S&LE`#^7iAX-^Je˧#D`o5ᜏyx6E&Ҹ=,ya2ξz.u}-mLq|+浩ݦW\%uO"Fd#ݺ$p]@$b.!^bk F[=AW/jnqx+۾Q""CAvyRAfoXj$npaP}K1dH֒H 7VD&)j!xJ+LAtwOh4[[-dF\f*j:AMY8:\x̅hPg>yq;/wN7DkFQG%V|CI[V~ \=cJf4VӢk!-1ig _@-S=s +ȩ($sr3]n(ݹo!q "X[Z>q,t_? E" x>-wĶ4 y6w$.bt" UM;PWe&"/(6vqaxbӢ C#6?]زyM)ԇJjUˏ(q5Q"lm* ]E*vT\vL,wLX/[l05a'5c 3]M8: [gZv Lٚ@nq*̄Du8kv)\uB;HW>CQ9BzuO3NoC ЂA-乭=cKv ^ VB +W^p)W:ۙsEYb'o{.^y]&}Hqv"+/>M7B3ڳge$Aif[ ұ~YdQtZ.-2I:h,~s ` +sqxKP7D6%٤\taSV2K`/u/z!#H Tc$"!_F:L Msn(Λs +?|K j9wo`DYs2ա ͫ:ˑiwPv:%9o/i[BhEl+?dit1JQe.yK)nEmOڟNn_p" Ytb=}2ymxv][tRĺqq^EN#[G;u,z{4DžRCW,=䱖m\ #t2M(d({=Ym )1zd!M B,(uI+[̈dH/c{C"+I8CP- >>-Lgf̌7ttq@Zgjbݧ AmSԭ*ZF{Pfhhyc4]QudB(ԩ%!٢uۣ?(f}^3;(qmܐ`wr_]f"l%cSH)^#tf%(Z"0d|Oy]fM^j ?aU7 -c~ D,.w؏ D#\BI!je:t3F +^ww#c!݇>휦TF؆KnL{ׁU8WMVk䈴_ŝ=TMGƎ%"egK3b*kWSme!n)%^ +-'#e5'0E+*Ŵwj?k8oRv-ʝU-2Oq'~.cq̥jEQP!laPz~靅 k ˔uLj۴XXm8pI~62W04`;ێ iC*/|FBM/f3cpE ($f2LˠĔP)f茽[A^S0?sh EFf<-OOϟ)@*d:(Cy6f +1 פqն{OK Z $`ZB굃4{*[4c#M?H >NUF񠓥kg zHlw#IR=eQDHXX 5"v ^,;z EAQd4Llل_׊HuU^PSo%كaٯiH^b^A]{dtM4AEPBϨHͺg*J%%H DGMADK~ܱtLIMhhHLt>N^ (2f\q#>C[IB+Dž@gOOGA.q]Djԃa @0olv7,a*K-SDl'j*w~xG7W7o.ߞ`^#g/o9WW߿~Rp>ֹ^gR&x8YjàqR񟽸3*R4/.ۛW$ͫ]ig=on{w#ysΧ]~}{7۟~÷o~a㋛o˷~s1ǟ,K_}|*>@9yߝCsN95?1MSv+?N˧/_0ҷ"=ċб!ZKF9 +deQ¿n1K6FPG;& Lp44'( 9T: XaZxt)$Dyz`)?8!CAwE8'pԩBT[%AQ|'']El g <RlJ㬌ln][P>ƿnR'bq"ONܥn^ ,fTR̲lD"'4^^W):3Ӆ9'OGV.ty:K`S +<HgjM4 $ja:"Z+$Yb9} VN*e<Hzn@Q;݈2vPGGO tkڲs.I:bGn$gIB<9*2@z?@N1Q$[-o yQ&-:pHQ6?9c=͐~#q $rr^HC/Mɘw1 ๊t0e@}@@Oy1GL#bR!0LYB;lKFcq//VihsfϾ mj۪֝x/k|(+$K ^R3Y[ 'ȶ|hcZpV}-֝3d> +uVF,WɢF(PZϞ=(-"O>s5Ε)Iޤhh@sE USXE;\pɲǙk8eUl gqՖUah%Lu<>Y}xI6CU~6#L>oe%TXQYA_@y$1 4Nݍ&-sEF ?5~aiKt +wm2rp˚RLwOM$P4LicT^P}$ށ5*TХrP,q0-+N(pb)O =)yAb=DkE;vqg]$iH&R9PhTr!:r^Ik>φfj"!V { :SQC/^ӵpH>\fwJtU8GF)ƕU +ҕҖ,h(*ڂ+L>Ix,RE*t@+@4'Oʶr*5Yscm>F +Δk$fiQPї:X%u}n{n]47\3)ZBK0* =7(# m OYʂABПJ3f޻4S*7NRogw/*/VZk·}gaGR3kGZ#v47@3:=Cgv[F'ʚT-3` +ؘטY։٧TJKQ2oS,'TX> &e74Lh9Xi$EaAwyѦU; < ƒF<9ZA]2**XřzC,fS:bx'%%8&$2o:(IͨXJ~~c¥t.Q^,p5JVmI;=X2rJHGʑҪrhk}3! +`HaU0j^HK9(b@&j6IP&OF_Q]V sYjtMpѭӧfU@dagB>Ps#j + 5V4;yR, 5tZ#6!#f<=PiLO7z1L,eX{5c+V̌_x{;`uE'#(J\)]$iNYThLԺpf:J5ˈ,rPT j‚>(H6RL:4zG@rY(:P;93 XwW^[㦤A ,epy9Z]FbEv@h$=ӀՅ&] i2a \Ґi镺?[- D?D"4isۻisTdY[|FP$rfDL5-:8TJ "vܢº(!,™8*8%*@f3 +&`>*Ci,q'ͫ;u.4WǮf3PQVv39Χ N񕾟4]M['Ɏj?miǰ:Bmg yJNUS%Y^*E> J:eDEpJ5I[Lj)JSn-hBMW17='1*.-KQ Qy +8;ŅD9-P@^7=t6 e-\D(RYgd9sEjMADM-~/ )ve) +sW, P{RAAjgyXtCQe)tEVL쉛h[UkQ(Af,Gx襱7rUK`9{j(S)QeR{K,(^+H) 7We90.q){xfU{ceh\ A+v":+- : x|_Ӿo"q%kˆ#I-9Qi'K(#Q@jwypƾ}t +AzT+/se$*NL] + +Gouy8O>% +kc#7ɗlQ^=Smsۋ[OaBн@ ;V()p+fZ,#!.B݋O}vGɗwۃ_洽zs\lW7.n?jf*iUܬLӋ_^Yv~wwq{}<{}ח?~q{/}^xy/ZOۃճwW?ܼSr}Zzzj?ogwO~R!oxgoZn_o~W)C-z5gU?d$Ԋ合+~nWKe9]A!=lK=䨠YQS[_(H8_:v6#W~o(mgo9rRG%URq$S*V> 2%C j9ur} ~ +Jtn+#l<uz$NvGhjПױBFfӴ[{U;{v?mQ  PE}!Ê +ui$'1jaָ%tRpujR:@8 +)hӹ,hS(FΘ/T~b. E:fuGa GWU[3o/V4KDy?g}) +U8KpzֺM'$]➦Rmg9@^ય$TWc]%ד^JQȆqIh0 撵\ 3E,N J!% THXY`9k+tDI3\!zAN2g4k⚦_ +0:f u͂Vype~;:Df*#\ќ>QʫZzTx^+ +@H-&sh UnXhZI{T=|T`*9^ F957:{OQ́\!jdǛeG8 U>oO.._Bim* ҨNj5;?sbltF=<-kH~EY]􃔩SBGs}Ag|eOS<6+4&T#us6Ay0"3A7 +RKzФMPz:v!H:=|myI˸!?:u8ʭ D=cLYMT"E>J`itE[r3]&b9aO[|9U>xT:te=\߃C 8sp Φ+ӏQ9'n\ KKnEVo:tM㖌V:OzB$컉b_W#(4YjuQ7ć6ju!Í%pm#Ι]Wvx)\dߐYWyB(a_ot[S"?s|K9@Ck ^tv+:sct燌ķ.}!d6#J]w%.^t?h%w A)9%VW46j!‰BWS9AԴAX&uic1E ckR!YK(YB(dLof]ASʐ~ '4<ʸ/|c숷2"$+/HO m8nͳIq,XnyFe\,Y;4: \RRA pt%)U@sA\.BS>j y ﰇ$ؒ/; +B)%4}Jdgdo[uT9ûyBBD"HRvkZTKwe.Z^L!)N{\OF~=o> %tؙWjqBt~gj'K:͊]bZEkU=o Z`.)v-zر6iifٖz[rqZ9^;A3;Z +j ѹӑ/%xtݟ*&` Zq<6r j:@TD@P?h4dl_ wDuB1j@2΄0g{!C MWP#\?TXcka&3S{Dd*lZS&خZ8EOWE[p/%ik n;A\YocʖLSM:尻jcEϰIp=@{+?H~FpbJV[>y-˘//[!; l>ؠ+BT8jiiwhXH +|Z5 p9ztFHhOzg|iGvjNv(~@@.Geg.\g_tq@X7lX {>~P(NϯK%֭|l{$24/n__\49?$I?xkT95{W~W?7oFHwbF  G3GH_?|?a 1g,>9 +Zfuuc$S$k9<ijgOkZlǕ_X+ t5VQQ<7GQ(&Z%Q  |ˏw<홢`J YY܊7. +Ͳ-55>Ֆ6ŝ>\ vB=;$-T^POf`tf4hk<dYᄠ'H"%'f$'t=k kuԼ`fѦT&9K.dZ}hє||m|~HұM.9BPblT~__[7LkzcKڙdkNFu{AF:QF=e;nX9m10FG*;[º{ar,Y w3l;d%-չ A9.dr8ƑhrA[Z;i}>EY"(V([GaZXYΏhc;~'YȨdo&賌RG7w3_t4siе'z(|{Q^>̥%|v©~BuК4 l-Xܑƴ[dv'qύ&ն[j$vyKmL^b9m-2d}>A!ᵜ*됕X5B(F.V:nR9o׋yos2H\INtƒwa~_Fw٠>~SVH~֜^Ә5>i&; p6IfT }%AYi컞9)83&7L%!Pf1ر*hE j7bikf%w-=),keF,`v46?C^"6SuSd9wCu]R׹aw3a3ke̐)_hPtVA-%= ײC,>KqIh_KÔR;^CuuCύlXp#]y!RG Xto7IYsB,eۈ-O +2DcmSSl1)UO;$BTTdT[${[`-̸`4J G$mmF#f,A"W(nӨI*un9PdABѩ5wC{-"NDR?-O]>CO5h/R>(yKUk4=]*ʔI j3I[;z$B9[|S"iLJv]]U7|߷rw ]" J*ۭi@~lz1,[jaXz1QdPLJZkY"t›{yφ8CMW?^%Ϙ{FU`ݬTvs>k7fɞkۍeXM5^%6kxS 3J>tiHZN~B +a ͊\nCe5J]h|jVR@D1s3T\MSz/PYo 2~o`g<9G!?@vXt O>WisQ~R ou2;Vt(VҀMdlBU|( ӟZ[1cKsdH9hPٙ|L1%Dǐ6:7CN<5tҋJSY2MP$+rwFm[5~c;=%nhʙӺZ<^|S:vXD[j 94TT-J3Wt98E%S? j ;"ehktvRZ p=h,фCRiݮ>\xzq|DkԎ\. ;ț U ]*_gf3(r)uf`[K^oW^b?Fs!Lj.=LcGi@Du^﷟PGH +endstream endobj 5 0 obj <> endobj 6 0 obj <> endobj 21 0 obj [/View/Design] endobj 22 0 obj <>>> endobj 19 0 obj [/View/Design] endobj 20 0 obj <>>> endobj 40 0 obj [38 0 R 39 0 R] endobj 69 0 obj <> endobj xref +0 70 +0000000004 65535 f +0000000016 00000 n +0000000190 00000 n +0000049746 00000 n +0000000000 00000 f +0000258139 00000 n +0000258209 00000 n +0000000000 00000 f +0000049797 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000258394 00000 n +0000258425 00000 n +0000258278 00000 n +0000258309 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000052605 00000 n +0000052534 00000 n +0000258510 00000 n +0000050188 00000 n +0000050900 00000 n +0000053030 00000 n +0000052421 00000 n +0000052907 00000 n +0000051934 00000 n +0000050965 00000 n +0000051372 00000 n +0000051420 00000 n +0000052358 00000 n +0000052791 00000 n +0000052822 00000 n +0000052675 00000 n +0000052706 00000 n +0000053104 00000 n +0000053516 00000 n +0000054601 00000 n +0000075356 00000 n +0000082214 00000 n +0000098911 00000 n +0000111506 00000 n +0000128860 00000 n +0000150154 00000 n +0000165047 00000 n +0000168853 00000 n +0000182581 00000 n +0000207793 00000 n +0000235522 00000 n +0000258542 00000 n +trailer +<<6F5B9B7F453C604DB2C173BD730E74F6>]>> +startxref +258711 +%%EOF diff --git a/ZRCola/stdafx.h b/ZRCola/stdafx.h index ac441da..b690cec 100644 --- a/ZRCola/stdafx.h +++ b/ZRCola/stdafx.h @@ -29,6 +29,7 @@ #include #include +#include #include #include diff --git a/ZRCola/zrcolaapp.cpp b/ZRCola/zrcolaapp.cpp index 3fafe1f..77519e8 100644 --- a/ZRCola/zrcolaapp.cpp +++ b/ZRCola/zrcolaapp.cpp @@ -60,7 +60,7 @@ bool ZRColaApp::OnInit() if (wxConfigBase::Get()->Read(wxT("LocalizationRepositoryPath"), &sPath)) m_locale.AddCatalogLookupPathPrefix(sPath); wxVERIFY(m_locale.Init(language)); - wxVERIFY(m_locale.AddCatalog(wxT("wxExtend"))); + wxVERIFY(m_locale.AddCatalog(wxT("wxExtend") wxT(wxExtendVersion))); wxVERIFY(m_locale.AddCatalog(wxT("libZRColaUI"))); wxVERIFY(m_locale.AddCatalog(wxT("ZRCola"))); wxVERIFY(m_locale.AddCatalog(wxT("ZRCola-zrcdb"))); @@ -128,7 +128,8 @@ bool ZRColaApp::OnInit() m_cc_db.idxRnk .clear(); m_cc_db.data .clear(); } - } + } else + stdex::idrec::ignore(dat); } if (!has_translation_data) diff --git a/ZRCola/zrcolachrcatpnl.cpp b/ZRCola/zrcolachrcatpnl.cpp index 1eab092..9ba318d 100644 --- a/ZRCola/zrcolachrcatpnl.cpp +++ b/ZRCola/zrcolachrcatpnl.cpp @@ -112,7 +112,9 @@ void wxZRColaCharacterCatalogPanel::OnGridClick(wxGridEvent& event) void wxZRColaCharacterCatalogPanel::OnGridKeyDown(wxKeyEvent& event) { - if (event.GetKeyCode() == WXK_RETURN) { + switch (event.GetKeyCode()) { + case WXK_RETURN: + case WXK_NUMPAD_ENTER: ZRColaApp *app = (ZRColaApp*)wxTheApp; if (app->m_mainWnd) { app->m_mainWnd->m_panel->m_decomposed->WriteText(m_grid->GetCellValue(m_grid->GetCursorRow(), m_grid->GetCursorColumn())); diff --git a/ZRCola/zrcolachrgrid.cpp b/ZRCola/zrcolachrgrid.cpp index ba3893c..f47439f 100644 --- a/ZRCola/zrcolachrgrid.cpp +++ b/ZRCola/zrcolachrgrid.cpp @@ -44,7 +44,7 @@ wxZRColaCharGrid::wxZRColaCharGrid(wxWindow *parent, wxWindowID id, const wxPoin SetDefaultRowSize(wxZRColaCharacterGridRowHeight); // Create timer for saving the state. - m_toolTipTimer = new wxTimer(this, wxID_TOOLTIP_TIMER); + m_timerToolTip.SetOwner(this, wxID_TOOLTIP_TIMER); // wxEVT_MOTION event must be connected to the wxGridWindow, not wxGrid itself. wxWindow *gridWnd = GetGridWindow(); @@ -56,16 +56,12 @@ wxZRColaCharGrid::~wxZRColaCharGrid() { wxWindow *gridWnd = GetGridWindow(); gridWnd->Disconnect(gridWnd->GetId(), wxEVT_MOTION, wxMouseEventHandler(wxZRColaCharGrid::OnMotion), NULL, this); - - if (m_toolTipTimer) - delete m_toolTipTimer; } void wxZRColaCharGrid::Init() { m_isResizing = false; - m_toolTipTimer = NULL; m_toolTipIdx = (size_t)-1; } @@ -147,12 +143,15 @@ void wxZRColaCharGrid::OnSize(wxSizeEvent& event) SetTable(table, true); } - // Set column widths to stretch to full width. - for (int c = 0, x_l = 0; c < cols; c++) { - int x_r = (c + 1)*width/cols; - SetColSize(c, x_r - x_l); - x_l = x_r; - } + for (int c = 0; c < cols; c++) + SetColSize(c, wxZRColaCharacterGridColumnWidth); + + //// Set column widths to stretch to full width. + //for (int c = 0, x_l = 0; c < cols; c++) { + // int x_r = (c + 1)*width/cols; + // SetColSize(c, x_r - x_l); + // x_l = x_r; + //} EndBatch(); m_isResizing = false; @@ -193,7 +192,7 @@ void wxZRColaCharGrid::OnMotion(wxMouseEvent& event) if (toolTipIdx >= m_chars.Length()) { // Index out of range. m_toolTipIdx = (size_t)-1; - m_toolTipTimer->Stop(); + m_timerToolTip.Stop(); return; } else if (toolTipIdx != m_toolTipIdx) { // Cell changed. @@ -204,7 +203,7 @@ void wxZRColaCharGrid::OnMotion(wxMouseEvent& event) gridWnd->SetToolTip(GetToolTipText(m_toolTipIdx)); } else { // This must be our initial entry. Schedule tooltip display after 1s. - m_toolTipTimer->Start(1000, true); + m_timerToolTip.Start(1000, true); } } } diff --git a/ZRCola/zrcolachrgrid.h b/ZRCola/zrcolachrgrid.h index 4957118..35713f5 100644 --- a/ZRCola/zrcolachrgrid.h +++ b/ZRCola/zrcolachrgrid.h @@ -58,6 +58,16 @@ public: /// void SetCharacters(const wxString &chars); + /// + /// Returns displayed characters + /// + /// \returns The string containing displayed characters + /// + inline wxString GetCharacters() const + { + return m_chars; + } + protected: virtual wxString GetToolTipText(int idx); @@ -75,6 +85,6 @@ protected: private: bool m_isResizing; ///< Prevents nesting of OnSize() method. - wxTimer *m_toolTipTimer;///< Timer for displaying tooltip + wxTimer m_timerToolTip; ///< Timer for displaying tooltip size_t m_toolTipIdx; ///< Index of cell for tooltip display }; diff --git a/ZRCola/zrcolachrslct.cpp b/ZRCola/zrcolachrslct.cpp index 79a09fd..7ac160c 100644 --- a/ZRCola/zrcolachrslct.cpp +++ b/ZRCola/zrcolachrslct.cpp @@ -20,21 +20,301 @@ #include "stdafx.h" +static int __cdecl compare_hits(const void *a, const void *b) +{ + const std::pair *_a = (const std::pair*)a; + const std::pair *_b = (const std::pair*)b; + + if (_a->first > _b->first) return -1; + else if (_a->first < _b->first) return 1; + + if (_a->second < _b->second) return -1; + else if (_a->second > _b->second) return 1; + + return 0; +} + + + ////////////////////////////////////////////////////////////////////////// // wxZRColaCharSelect ////////////////////////////////////////////////////////////////////////// -wxZRColaCharSelect::wxZRColaCharSelect(wxWindow* parent) : wxZRColaCharSelectBase(parent) +wxZRColaCharSelect::wxZRColaCharSelect(wxWindow* parent) : + m_searchChanged(false), + m_unicodeChanged(false), + m_char(0), + wxZRColaCharSelectBase(parent) { - wxTextValidator *validator = dynamic_cast(m_unicode->GetValidator()); - if (validator) - validator->SetCharIncludes(wxT("0123456789ABCDEFabcdef")); + m_unicode->SetValidator(wxHexValidator(&m_char)); + // Fill categories. ZRColaApp *app = (ZRColaApp*)wxTheApp; - for (size_t i = 0, n = app->m_cc_db.idxRnk.size(); i < n; i++) { + size_t i, n; + for (i = 0, n = app->m_cc_db.idxRnk.size(); i < n; i++) { const ZRCola::chrcat_db::chrcat &cc = app->m_cc_db.idxRnk[i]; - m_categories->Check(m_categories->Insert(wxGetTranslation(wxString(cc.name, cc.name_len), wxT("ZRCola-zrcdb")), i)); + int idx = m_categories->Insert(wxGetTranslation(wxString(cc.name, cc.name_len), wxT("ZRCola-zrcdb")), i); + m_categories->Check(idx); + m_ccOrder.insert(std::make_pair(cc.id, idx)); } + + ResetResults(); +} + + +void wxZRColaCharSelect::OnIdle(wxIdleEvent& event) +{ + event.Skip(); + + if (m_unicodeChanged) { + if (m_unicode->GetValidator()->TransferFromWindow()) { + ZRColaApp *app = (ZRColaApp*)wxTheApp; + + m_gridPreview->SetCellValue(wxString(1, m_char), 0, 0); + + { + ZRCola::character_db::character *chr = (ZRCola::character_db::character*)new char[sizeof(ZRCola::character_db::character)]; + chr->chr = m_char; + size_t start, end; + if (app->m_chr_db.idxChr.find(*chr, start, end)) { + const ZRCola::character_db::character &chr = app->m_chr_db.idxChr[start]; + m_description->SetValue(wxString(chr.data, chr.desc_len)); + m_gridRelated->SetCharacters(wxString(chr.data + chr.desc_len, chr.rel_len)); + } else { + m_description->SetValue(wxEmptyString); + m_gridRelated->ClearGrid(); + } + m_gridRelated->Scroll(0, 0); + delete chr; + } + } + + m_unicodeChanged = false; + } else if (m_searchChanged) { + m_timerSearch.Start(1000, true); + + m_searchChanged = false; + } +} + + +void wxZRColaCharSelect::OnSearchText(wxCommandEvent& event) +{ + event.Skip(); + + m_timerSearch.Stop(); + m_searchChanged = true; +} + + +void wxZRColaCharSelect::OnSearchEnter(wxCommandEvent& event) +{ + event.Skip(); + + m_timerSearch.Stop(); + wxTimerEvent e(m_timerSearch); + GetEventHandler()->ProcessEvent(e); + + m_searchChanged = false; +} + + +void wxZRColaCharSelect::OnSearchTimer(wxTimerEvent& event) +{ + wxString val(m_search->GetValue()); + if (!val.IsEmpty()) { + ZRColaApp *app = (ZRColaApp*)wxTheApp; + std::map hits; + + { + // Search by indexes and merge results. + std::map hits_sub; + app->m_chr_db.search_by_desc(val.c_str(), hits, hits_sub); + for (std::map::const_iterator i = hits_sub.cbegin(), i_end = hits_sub.cend(); i != i_end; ++i) { + std::map::iterator idx = hits.find(i->first); + if (idx == hits.end()) + hits.insert(std::make_pair(i->first, i->second / 4)); + else + idx->second += i->second / 4; + } + } + + // Filter by categories. + ZRCola::character_db::character *chr = (ZRCola::character_db::character*)new char[sizeof(ZRCola::character_db::character)]; + for (std::map::const_iterator i = hits.cbegin(), i_end = hits.cend(); i != i_end;) { + chr->chr = i->first; + size_t start, end; + std::map::const_iterator idx; + if (app->m_chr_db.idxChr.find(*chr, start, end) && + ((idx = m_ccOrder.find(app->m_chr_db.idxChr[start].cat)) == m_ccOrder.end() || m_categories->IsChecked(idx->second))) + { + // Character category approved. + ++i; + } else { + // Character category not approved. + std::map::const_iterator i_remove = i; + ++i; + hits.erase(i_remove); + } + } + delete chr; + + // Now sort the characters by rank. + std::vector< std::pair > hits2; + hits2.reserve(hits.size()); + for (std::map::const_iterator i = hits.cbegin(), i_end = hits.cend(); i != i_end; ++i) + hits2.push_back(std::make_pair(i->second, i->first)); + std::qsort(hits2.data(), hits2.size(), sizeof(std::pair), compare_hits); + + // Display results. + wxString chars; + chars.reserve(hits2.size()); + for (std::vector< std::pair >::const_iterator i = hits2.cbegin(), i_end = hits2.cend(); i != i_end; ++i) + chars += i->second; + m_gridResults->SetCharacters(chars); + } else + ResetResults(); + + m_gridResults->Scroll(0, 0); +} + + +void wxZRColaCharSelect::OnCategoriesToggle(wxCommandEvent& event) +{ + m_timerSearch.Stop(); + m_timerSearch.Start(500, true); +} + + +void wxZRColaCharSelect::OnResultSelectCell(wxGridEvent& event) +{ + wxString val(m_gridResults->GetCellValue(event.GetRow(), event.GetCol())); + m_char = val.IsEmpty() ? 0 : val[0]; + m_unicode->GetValidator()->TransferToWindow(); +} + + +void wxZRColaCharSelect::OnResultCellDClick(wxGridEvent& event) +{ + event.Skip(); + + wxString val(m_gridResults->GetCellValue(event.GetRow(), event.GetCol())); + if (!val.IsEmpty()) { + m_char = val[0]; + wxCommandEvent e(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK); + m_sdbSizerButtonsOK->GetEventHandler()->ProcessEvent(e); + } +} + + +void wxZRColaCharSelect::OnResultsKeyDown(wxKeyEvent& event) +{ + switch (event.GetKeyCode()) { + case WXK_RETURN: + case WXK_NUMPAD_ENTER: + wxString val(m_gridResults->GetCellValue(m_gridResults->GetCursorRow(), m_gridResults->GetCursorColumn())); + if (!val.IsEmpty()) { + m_char = val[0]; + wxCommandEvent e(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK); + m_sdbSizerButtonsOK->GetEventHandler()->ProcessEvent(e); + + event.StopPropagation(); + return; + } + } + + event.Skip(); +} + + +void wxZRColaCharSelect::OnRecentSelectCell(wxGridEvent& event) +{ + wxString val(m_gridRecent->GetCellValue(event.GetRow(), event.GetCol())); + m_char = val.IsEmpty() ? 0 : val[0]; + m_unicode->GetValidator()->TransferToWindow(); +} + + +void wxZRColaCharSelect::OnRecentCellDClick(wxGridEvent& event) +{ + event.Skip(); + + wxString val(m_gridRecent->GetCellValue(event.GetRow(), event.GetCol())); + if (!val.IsEmpty()) { + m_char = val[0]; + wxCommandEvent e(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK); + m_sdbSizerButtonsOK->GetEventHandler()->ProcessEvent(e); + } +} + + +void wxZRColaCharSelect::OnRecentKeyDown(wxKeyEvent& event) +{ + switch (event.GetKeyCode()) { + case WXK_RETURN: + case WXK_NUMPAD_ENTER: + wxString val(m_gridRecent->GetCellValue(m_gridRecent->GetCursorRow(), m_gridRecent->GetCursorColumn())); + if (!val.IsEmpty()) { + m_char = val[0]; + wxCommandEvent e(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK); + m_sdbSizerButtonsOK->GetEventHandler()->ProcessEvent(e); + + event.StopPropagation(); + return; + } + } + + event.Skip(); +} + + +void wxZRColaCharSelect::OnRelatedSelectCell(wxGridEvent& event) +{ + wxString val(m_gridRelated->GetCellValue(event.GetRow(), event.GetCol())); + m_char = val.IsEmpty() ? 0 : val[0]; + m_unicode->GetValidator()->TransferToWindow(); +} + + +void wxZRColaCharSelect::OnUnicodeText(wxCommandEvent& event) +{ + event.Skip(); + + m_unicodeChanged = true; +} + + +void wxZRColaCharSelect::OnOKButtonClick(wxCommandEvent& event) +{ + event.Skip(); + + wxString + recent(m_gridRecent->GetCharacters()), + val(1, m_char); + for (size_t i = 0, n = recent.Length(); i < n; i++) { + const wxStringCharType c = recent[i]; + if (c != m_char) + val += c; + } + + m_gridRecent->SetCharacters(val); +} + + +void wxZRColaCharSelect::ResetResults() +{ + // Fill the results. + ZRColaApp *app = (ZRColaApp*)wxTheApp; + size_t i, n = app->m_chr_db.idxChr.size(); + wxString val; + val.reserve(n); + for (i = 0; i < n; i++) { + const ZRCola::character_db::character &chr = app->m_chr_db.idxChr[i]; + std::map::const_iterator idx = m_ccOrder.find(chr.cat); + if (idx == m_ccOrder.end() || m_categories->IsChecked(idx->second)) + val += chr.chr; + } + m_gridResults->SetCharacters(val); } @@ -42,25 +322,26 @@ wxZRColaCharSelect::wxZRColaCharSelect(wxWindow* parent) : wxZRColaCharSelectBas // wxPersistentZRColaCharSelect ////////////////////////////////////////////////////////////////////////// -wxPersistentZRColaCharSelect::wxPersistentZRColaCharSelect(wxZRColaCharSelect *wnd) : wxPersistentWindow(wnd) +wxPersistentZRColaCharSelect::wxPersistentZRColaCharSelect(wxZRColaCharSelect *wnd) : wxPersistentDialog(wnd) { } -wxString wxPersistentZRColaCharSelect::GetKind() const -{ - return wxT(wxPERSIST_TLW_KIND); -} - - void wxPersistentZRColaCharSelect::Save() const { + wxPersistentDialog::Save(); + const wxZRColaCharSelect * const wnd = static_cast(GetWindow()); - // Code copied from wxPersistentTLW::Save() - const wxPoint pos = wnd->GetScreenPosition(); - SaveValue(wxPERSIST_TLW_X, pos.x); - SaveValue(wxPERSIST_TLW_Y, pos.y); + SaveValue(wxT("recentChars"), wnd->m_gridRecent->GetCharacters()); + + ZRColaApp *app = (ZRColaApp*)wxTheApp; + for (size_t i = 0, n = app->m_cc_db.idxRnk.size(); i < n; i++) { + const ZRCola::chrcat_db::chrcat &cc = app->m_cc_db.idxRnk[i]; + wxString name(wxT("category")); + name.Append(cc.id.data, _countof(cc.id.data)); + SaveValue(name, wnd->m_categories->IsChecked(i)); + } } @@ -68,28 +349,20 @@ bool wxPersistentZRColaCharSelect::Restore() { wxZRColaCharSelect * const wnd = static_cast(GetWindow()); - // Code copied from wxPersistentTLW::Restore() - long - x wxDUMMY_INITIALIZE(-1), - y wxDUMMY_INITIALIZE(-1); - const wxSize size = wnd->GetSize(); - const bool hasPos = RestoreValue(wxPERSIST_TLW_X, &x) && - RestoreValue(wxPERSIST_TLW_Y, &y); + wxString recent; + if (RestoreValue(wxT("recentChars"), &recent)) + wnd->m_gridRecent->SetCharacters(recent); - if (hasPos) { - // to avoid making the window completely invisible if it had been - // shown on a monitor which was disconnected since the last run - // (this is pretty common for notebook with external displays) - // - // NB: we should allow window position to be (slightly) off screen, - // it's not uncommon to position the window so that its upper - // left corner has slightly negative coordinate - if (wxDisplay::GetFromPoint(wxPoint(x , y )) != wxNOT_FOUND || - wxDisplay::GetFromPoint(wxPoint(x + size.x, y + size.y)) != wxNOT_FOUND) - { - wnd->Move(x, y, wxSIZE_ALLOW_MINUS_ONE); - } + ZRColaApp *app = (ZRColaApp*)wxTheApp; + for (size_t i = 0, n = app->m_cc_db.idxRnk.size(); i < n; i++) { + const ZRCola::chrcat_db::chrcat &cc = app->m_cc_db.idxRnk[i]; + wxString name(wxT("category")); + name.Append(cc.id.data, _countof(cc.id.data)); + bool val; + if (RestoreValue(name, &val)) + wnd->m_categories->Check(i, val); } + wnd->ResetResults(); - return true; + return wxPersistentDialog::Restore(); } diff --git a/ZRCola/zrcolachrslct.h b/ZRCola/zrcolachrslct.h index 48d765e..6b2ef91 100644 --- a/ZRCola/zrcolachrslct.h +++ b/ZRCola/zrcolachrslct.h @@ -27,6 +27,10 @@ class wxZRColaCharSelect; #pragma once #include "zrcolagui.h" +#include +#include +#include +#include /// @@ -36,18 +40,45 @@ class wxZRColaCharSelect : public wxZRColaCharSelectBase { public: wxZRColaCharSelect(wxWindow* parent); + + friend class wxPersistentZRColaCharSelect; // Allow saving/restoring window state. + +protected: + virtual void OnIdle(wxIdleEvent& event); + virtual void OnSearchText(wxCommandEvent& event); + virtual void OnSearchEnter(wxCommandEvent& event); + virtual void OnSearchTimer(wxTimerEvent& event); + virtual void OnCategoriesToggle(wxCommandEvent& event); + virtual void OnResultSelectCell(wxGridEvent& event); + virtual void OnResultCellDClick(wxGridEvent& event); + virtual void OnResultsKeyDown(wxKeyEvent& event); + virtual void OnRecentSelectCell(wxGridEvent& event); + virtual void OnRecentCellDClick(wxGridEvent& event); + virtual void OnRecentKeyDown(wxKeyEvent& event); + virtual void OnRelatedSelectCell(wxGridEvent& event); + virtual void OnUnicodeText(wxCommandEvent& event); + virtual void OnOKButtonClick(wxCommandEvent& event); + + void ResetResults(); + +public: + wchar_t m_char; ///< Currently selected character (0 when none) + +protected: + bool m_searchChanged; ///< Did Search field change? + std::map m_ccOrder; ///< Character category order + bool m_unicodeChanged; ///< Did Unicode field change? }; /// /// Supports saving/restoring wxZRColaCharSelect state /// -class wxPersistentZRColaCharSelect : public wxPersistentWindow +class wxPersistentZRColaCharSelect : public wxPersistentDialog { public: wxPersistentZRColaCharSelect(wxZRColaCharSelect *wnd); - virtual wxString GetKind() const; virtual void Save() const; virtual bool Restore(); }; diff --git a/ZRCola/zrcolacomppnl.cpp b/ZRCola/zrcolacomppnl.cpp index fd29337..f34aeab 100644 --- a/ZRCola/zrcolacomppnl.cpp +++ b/ZRCola/zrcolacomppnl.cpp @@ -24,11 +24,6 @@ // wxZRColaComposerPanel ////////////////////////////////////////////////////////////////////////// -BEGIN_EVENT_TABLE(wxZRColaComposerPanel, wxZRColaComposerPanelBase) - EVT_TIMER(wxZRColaComposerPanel::wxID_CHECKPOINT_TIMER, wxZRColaComposerPanel::OnTimerTimeout) -END_EVENT_TABLE() - - wxZRColaComposerPanel::wxZRColaComposerPanel(wxWindow* parent) : m_decomposedChanged(false), m_composedChanged(false), @@ -38,9 +33,6 @@ wxZRColaComposerPanel::wxZRColaComposerPanel(wxWindow* parent) : { m_decomposed->PushEventHandler(&m_keyhandler); - // Create timer for saving the state. - m_timer = new wxTimer(this, wxID_CHECKPOINT_TIMER); - // Restore the previously saved state (if exists). wxString fileName(GetStateFileName()); if (wxFileExists(fileName)) { @@ -80,9 +72,6 @@ wxZRColaComposerPanel::wxZRColaComposerPanel(wxWindow* parent) : wxZRColaComposerPanel::~wxZRColaComposerPanel() { - if (m_timer) - delete m_timer; - m_decomposed->PopEventHandler(); // This is a controlled exit. Purge saved state. @@ -95,7 +84,7 @@ wxZRColaComposerPanel::~wxZRColaComposerPanel() void wxZRColaComposerPanel::SynchronizePanels() { if (m_decomposedChanged) { - m_timer->Stop(); + m_timerSave.Stop(); wxString src; size_t len = GetValue(m_decomposed, src); @@ -119,9 +108,9 @@ void wxZRColaComposerPanel::SynchronizePanels() SetHexValue(m_composedHex, m_selComposedHex, m_mappingComposedHex, dst.data(), dst.length(), m_selComposed.first, m_selComposed.second); // Schedule state save after 3s. - m_timer->Start(3000, true); + m_timerSave.Start(3000, true); } else if (m_composedChanged) { - m_timer->Stop(); + m_timerSave.Stop(); wxString src; size_t len = GetValue(m_composed, src); @@ -150,7 +139,7 @@ void wxZRColaComposerPanel::SynchronizePanels() SetHexValue(m_decomposedHex, m_selDecomposedHex, m_mappingDecomposedHex, dst.data(), dst.length(), m_selDecomposed.first, m_selDecomposed.second); // Schedule state save after 3s. - m_timer->Start(3000, true); + m_timerSave.Start(3000, true); } m_decomposedChanged = false; @@ -285,7 +274,7 @@ void wxZRColaComposerPanel::OnComposedText(wxCommandEvent& event) } -void wxZRColaComposerPanel::OnTimerTimeout(wxTimerEvent& event) +void wxZRColaComposerPanel::OnSaveTimer(wxTimerEvent& event) { wxString fileName(GetStateFileName()); wxFFile file(fileName, wxT("wb")); diff --git a/ZRCola/zrcolacomppnl.h b/ZRCola/zrcolacomppnl.h index 01d163d..2dbd939 100644 --- a/ZRCola/zrcolacomppnl.h +++ b/ZRCola/zrcolacomppnl.h @@ -38,11 +38,6 @@ class wxZRColaComposerPanel; class wxZRColaComposerPanel : public wxZRColaComposerPanelBase { public: - enum - { - wxID_CHECKPOINT_TIMER = 2000, - }; - wxZRColaComposerPanel(wxWindow* parent); virtual ~wxZRColaComposerPanel(); @@ -57,8 +52,7 @@ protected: virtual void OnComposedPaint(wxPaintEvent& event); virtual void OnComposedHexPaint(wxPaintEvent& event); virtual void OnComposedText(wxCommandEvent& event); - virtual void OnTimerTimeout(wxTimerEvent& event); - DECLARE_EVENT_TABLE() + virtual void OnSaveTimer(wxTimerEvent& event); static wxString GetStateFileName(); static size_t GetValue(wxTextCtrl *wnd, wxString &text); @@ -75,7 +69,6 @@ protected: m_selComposed, ///< Character index of selected text in composed text control m_selComposedHex; ///< Character index of selected text in composed HEX dump text control wxZRColaKeyHandler m_keyhandler; ///< Key handler for decomposed window - wxTimer *m_timer; ///< Timer to trigger the state save ZRCola::mapping_vector m_mappingDecomposedHex; ///< Character index mapping vector between decomposed text and its HEX dump ZRCola::mapping_vector m_mappingComposedHex; ///< Character index mapping vector between composed text and its HEX dump }; diff --git a/ZRCola/zrcolafrm.cpp b/ZRCola/zrcolafrm.cpp index e42c658..b3a4447 100644 --- a/ZRCola/zrcolafrm.cpp +++ b/ZRCola/zrcolafrm.cpp @@ -39,7 +39,7 @@ wxBEGIN_EVENT_TABLE(wxZRColaFrame, wxZRColaFrameBase) EVT_MENU (wxID_SEND_DECOMPOSED , wxZRColaFrame::OnSendDecomposed ) EVT_MENU (wxID_SEND_ABORT , wxZRColaFrame::OnSendAbort ) - EVT_MENU (wxID_INSERT_CHARACTER , wxZRColaFrame::OnInsertCharacter ) + EVT_MENU (wxID_CHARACTER_SELECTOR , wxZRColaFrame::OnInsertCharacter ) EVT_UPDATE_UI (wxID_DECOMP_LANG_AUTO , wxZRColaFrame::OnDecomposedLanguageAutoUpdate) EVT_MENU (wxID_DECOMP_LANG_AUTO , wxZRColaFrame::OnDecomposedLanguageAuto ) @@ -257,7 +257,10 @@ void wxZRColaFrame::OnForwardEvent(wxCommandEvent& event) void wxZRColaFrame::OnInsertCharacter(wxCommandEvent& event) { - m_chrSelect->ShowModal(); + if (m_chrSelect->ShowModal() == wxID_OK && m_chrSelect->m_char) { + m_panel->m_decomposed->WriteText(m_chrSelect->m_char); + m_panel->m_decomposed->SetFocus(); + } } diff --git a/ZRCola/zrcolagui.cpp b/ZRCola/zrcolagui.cpp index db8f6ad..39fa103 100644 --- a/ZRCola/zrcolagui.cpp +++ b/ZRCola/zrcolagui.cpp @@ -80,9 +80,14 @@ wxZRColaFrameBase::wxZRColaFrameBase( wxWindow* parent, wxWindowID id, const wxS m_menuEdit->AppendSeparator(); - wxMenuItem* m_menuInsertCharacter; - m_menuInsertCharacter = new wxMenuItem( m_menuEdit, wxID_INSERT_CHARACTER, wxString( _("&Insert Character...") ) + wxT('\t') + wxT("F8"), _("Display character selector to select character to insert into text"), wxITEM_NORMAL ); - m_menuEdit->Append( m_menuInsertCharacter ); + wxMenuItem* m_menuCharSelect; + m_menuCharSelect = new wxMenuItem( m_menuEdit, wxID_CHARACTER_SELECTOR, wxString( _("C&haracter Selector...") ) + wxT('\t') + wxT("F8"), _("Display character selector to select character to insert into text"), wxITEM_NORMAL ); + #ifdef __WXMSW__ + m_menuCharSelect->SetBitmaps( wxIcon( wxT("char_select.ico"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16 ) ); + #elif (defined( __WXGTK__ ) || defined( __WXOSX__ )) + m_menuCharSelect->SetBitmap( wxIcon( wxT("char_select.ico"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16 ) ); + #endif + m_menuEdit->Append( m_menuCharSelect ); m_menuEdit->AppendSeparator(); @@ -162,6 +167,8 @@ wxZRColaFrameBase::wxZRColaFrameBase( wxWindow* parent, wxWindowID id, const wxS m_mgr.AddPane( m_toolbarEdit, wxAuiPaneInfo().Name( wxT("toolbarEdit") ).Top().Caption( _("Edit") ).PinButton( true ).Dock().Resizable().FloatingSize( wxSize( -1,-1 ) ).LeftDockable( false ).RightDockable( false ).Row( 0 ).Layer( 1 ).ToolbarPane() ); m_toolbarCompose = new wxAuiToolBar( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_TB_HORZ_LAYOUT ); + m_toolCharSelect = m_toolbarCompose->AddTool( wxID_CHARACTER_SELECTOR, _("Character Selector"), wxIcon( wxT("char_select.ico"), wxBITMAP_TYPE_ICO_RESOURCE, 24, 24 ), wxNullBitmap, wxITEM_NORMAL, _("Character Selector"), _("Display character selector to select character to insert into text"), NULL ); + m_toolSendComposed = m_toolbarCompose->AddTool( wxID_SEND_COMPOSED, _("Send Composed"), wxIcon( wxT("send_composed.ico"), wxBITMAP_TYPE_ICO_RESOURCE, 24, 24 ), wxNullBitmap, wxITEM_NORMAL, _("Send Composed"), _("Send composed text to source window"), NULL ); m_toolSendDecomposed = m_toolbarCompose->AddTool( wxID_SEND_DECOMPOSED, _("Send Decomposed"), wxIcon( wxT("send_decomposed.ico"), wxBITMAP_TYPE_ICO_RESOURCE, 24, 24 ), wxNullBitmap, wxITEM_NORMAL, _("Send Decomposed"), _("Send decomposed text to source window"), NULL ); @@ -308,6 +315,7 @@ wxZRColaComposerPanelBase::wxZRColaComposerPanelBase( wxWindow* parent, wxWindow this->SetSizer( bSizerMain ); this->Layout(); bSizerMain->Fit( this ); + m_timerSave.SetOwner( this, wxID_TIMER_SAVE ); // Connect Events m_decomposed->Connect( wxEVT_PAINT, wxPaintEventHandler( wxZRColaComposerPanelBase::OnDecomposedPaint ), NULL, this ); @@ -316,6 +324,7 @@ wxZRColaComposerPanelBase::wxZRColaComposerPanelBase( wxWindow* parent, wxWindow m_composed->Connect( wxEVT_PAINT, wxPaintEventHandler( wxZRColaComposerPanelBase::OnComposedPaint ), NULL, this ); m_composed->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxZRColaComposerPanelBase::OnComposedText ), NULL, this ); m_composedHex->Connect( wxEVT_PAINT, wxPaintEventHandler( wxZRColaComposerPanelBase::OnComposedHexPaint ), NULL, this ); + this->Connect( wxID_TIMER_SAVE, wxEVT_TIMER, wxTimerEventHandler( wxZRColaComposerPanelBase::OnSaveTimer ) ); } wxZRColaComposerPanelBase::~wxZRColaComposerPanelBase() @@ -327,6 +336,7 @@ wxZRColaComposerPanelBase::~wxZRColaComposerPanelBase() m_composed->Disconnect( wxEVT_PAINT, wxPaintEventHandler( wxZRColaComposerPanelBase::OnComposedPaint ), NULL, this ); m_composed->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxZRColaComposerPanelBase::OnComposedText ), NULL, this ); m_composedHex->Disconnect( wxEVT_PAINT, wxPaintEventHandler( wxZRColaComposerPanelBase::OnComposedHexPaint ), NULL, this ); + this->Disconnect( wxID_TIMER_SAVE, wxEVT_TIMER, wxTimerEventHandler( wxZRColaComposerPanelBase::OnSaveTimer ) ); } @@ -406,7 +416,7 @@ wxZRColaCharSelectBase::wxZRColaCharSelectBase( wxWindow* parent, wxWindowID id, wxStaticBoxSizer* sbSizerBrowse; sbSizerBrowse = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("&Browse") ), wxVERTICAL ); - m_search = new wxSearchCtrl( sbSizerBrowse->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_search = new wxSearchCtrl( sbSizerBrowse->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); #ifndef __WXMAC__ m_search->ShowSearchButton( true ); #endif @@ -414,50 +424,25 @@ wxZRColaCharSelectBase::wxZRColaCharSelectBase( wxWindow* parent, wxWindowID id, sbSizerBrowse->Add( m_search, 0, wxALL|wxEXPAND, 5 ); wxArrayString m_categoriesChoices; - m_categories = new wxCheckListBox( sbSizerBrowse->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_categoriesChoices, 0 ); - m_categories->SetMaxSize( wxSize( -1,59 ) ); - + m_categories = new wxCheckListBox( sbSizerBrowse->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxSize( -1,60 ), m_categoriesChoices, 0 ); sbSizerBrowse->Add( m_categories, 0, wxALL|wxEXPAND, 5 ); - m_gridResults = new wxGrid( sbSizerBrowse->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_gridResults = new wxZRColaCharGrid( sbSizerBrowse->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxSTATIC_BORDER ); // Grid - m_gridResults->CreateGrid( 7, 16 ); + m_gridResults->CreateGrid( 0, 0 ); m_gridResults->EnableEditing( false ); - m_gridResults->EnableGridLines( true ); + m_gridResults->EnableGridLines( false ); m_gridResults->EnableDragGridSize( false ); m_gridResults->SetMargins( 0, 0 ); // Columns - m_gridResults->SetColSize( 0, 35 ); - m_gridResults->SetColSize( 1, 35 ); - m_gridResults->SetColSize( 2, 35 ); - m_gridResults->SetColSize( 3, 35 ); - m_gridResults->SetColSize( 4, 35 ); - m_gridResults->SetColSize( 5, 35 ); - m_gridResults->SetColSize( 6, 35 ); - m_gridResults->SetColSize( 7, 35 ); - m_gridResults->SetColSize( 8, 35 ); - m_gridResults->SetColSize( 9, 35 ); - m_gridResults->SetColSize( 10, 35 ); - m_gridResults->SetColSize( 11, 35 ); - m_gridResults->SetColSize( 12, 35 ); - m_gridResults->SetColSize( 13, 35 ); - m_gridResults->SetColSize( 14, 35 ); - m_gridResults->SetColSize( 15, 35 ); m_gridResults->EnableDragColMove( false ); m_gridResults->EnableDragColSize( false ); m_gridResults->SetColLabelSize( 0 ); m_gridResults->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Rows - m_gridResults->SetRowSize( 0, 35 ); - m_gridResults->SetRowSize( 1, 35 ); - m_gridResults->SetRowSize( 2, 35 ); - m_gridResults->SetRowSize( 3, 35 ); - m_gridResults->SetRowSize( 4, 35 ); - m_gridResults->SetRowSize( 5, 35 ); - m_gridResults->SetRowSize( 6, 35 ); m_gridResults->EnableDragRowSize( false ); m_gridResults->SetRowLabelSize( 0 ); m_gridResults->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); @@ -468,48 +453,33 @@ wxZRColaCharSelectBase::wxZRColaCharSelectBase( wxWindow* parent, wxWindowID id, m_gridResults->SetDefaultCellFont( wxFont( 20, 70, 90, 90, false, wxT("00 ZRCola") ) ); m_gridResults->SetDefaultCellAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); m_gridResults->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) ); + m_gridResults->SetMinSize( wxSize( 560,35 ) ); + m_gridResults->SetMaxSize( wxSize( 560,-1 ) ); - sbSizerBrowse->Add( m_gridResults, 0, wxALL|wxEXPAND, 5 ); + sbSizerBrowse->Add( m_gridResults, 1, wxALL|wxEXPAND, 5 ); - bSizerLeft->Add( sbSizerBrowse, 0, wxALL|wxEXPAND, 5 ); + bSizerLeft->Add( sbSizerBrowse, 1, wxALL|wxEXPAND, 5 ); wxStaticBoxSizer* sbSizerRecent; sbSizerRecent = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Re¢ly Used") ), wxVERTICAL ); - m_gridRecent = new wxGrid( sbSizerRecent->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_gridRecent = new wxZRColaCharGrid( sbSizerRecent->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxSize( -1,35 ), wxSTATIC_BORDER ); // Grid - m_gridRecent->CreateGrid( 1, 16 ); + m_gridRecent->CreateGrid( 0, 0 ); m_gridRecent->EnableEditing( false ); - m_gridRecent->EnableGridLines( true ); + m_gridRecent->EnableGridLines( false ); m_gridRecent->EnableDragGridSize( false ); m_gridRecent->SetMargins( 0, 0 ); // Columns - m_gridRecent->SetColSize( 0, 35 ); - m_gridRecent->SetColSize( 1, 35 ); - m_gridRecent->SetColSize( 2, 35 ); - m_gridRecent->SetColSize( 3, 35 ); - m_gridRecent->SetColSize( 4, 35 ); - m_gridRecent->SetColSize( 5, 35 ); - m_gridRecent->SetColSize( 6, 35 ); - m_gridRecent->SetColSize( 7, 35 ); - m_gridRecent->SetColSize( 8, 35 ); - m_gridRecent->SetColSize( 9, 35 ); - m_gridRecent->SetColSize( 10, 35 ); - m_gridRecent->SetColSize( 11, 35 ); - m_gridRecent->SetColSize( 12, 35 ); - m_gridRecent->SetColSize( 13, 35 ); - m_gridRecent->SetColSize( 14, 35 ); - m_gridRecent->SetColSize( 15, 35 ); m_gridRecent->EnableDragColMove( false ); m_gridRecent->EnableDragColSize( false ); m_gridRecent->SetColLabelSize( 0 ); m_gridRecent->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Rows - m_gridRecent->SetRowSize( 0, 35 ); m_gridRecent->EnableDragRowSize( false ); m_gridRecent->SetRowLabelSize( 0 ); m_gridRecent->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); @@ -521,7 +491,7 @@ wxZRColaCharSelectBase::wxZRColaCharSelectBase( wxWindow* parent, wxWindowID id, m_gridRecent->SetDefaultCellAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); m_gridRecent->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) ); - sbSizerRecent->Add( m_gridRecent, 0, wxALL, 5 ); + sbSizerRecent->Add( m_gridRecent, 0, wxALL|wxEXPAND, 5 ); bSizerLeft->Add( sbSizerRecent, 0, wxALL|wxEXPAND, 5 ); @@ -543,25 +513,22 @@ wxZRColaCharSelectBase::wxZRColaCharSelectBase( wxWindow* parent, wxWindowID id, bSizerUnicode->Add( m_labelUnicode, 0, wxALIGN_CENTER, 5 ); m_unicode = new wxTextCtrl( sbSizerPreview->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 50,-1 ), 0 ); - m_unicode->SetMaxLength( 4 ); - m_unicode->SetValidator( wxTextValidator( wxFILTER_INCLUDE_CHAR_LIST, &m_unicodeValid ) ); - bSizerUnicode->Add( m_unicode, 0, wxALIGN_CENTER, 5 ); sbSizerPreview->Add( bSizerUnicode, 0, wxALIGN_CENTER|wxALL, 5 ); - m_gridPreview = new wxGrid( sbSizerPreview->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_gridPreview = new wxGrid( sbSizerPreview->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSTATIC_BORDER ); // Grid m_gridPreview->CreateGrid( 1, 1 ); m_gridPreview->EnableEditing( false ); - m_gridPreview->EnableGridLines( true ); + m_gridPreview->EnableGridLines( false ); m_gridPreview->EnableDragGridSize( false ); m_gridPreview->SetMargins( 0, 0 ); // Columns - m_gridPreview->SetColSize( 0, 210 ); + m_gridPreview->SetColSize( 0, 200 ); m_gridPreview->EnableDragColMove( false ); m_gridPreview->EnableDragColSize( false ); m_gridPreview->SetColLabelSize( 0 ); @@ -576,44 +543,37 @@ wxZRColaCharSelectBase::wxZRColaCharSelectBase( wxWindow* parent, wxWindowID id, // Label Appearance // Cell Defaults - m_gridPreview->SetDefaultCellFont( wxFont( 180, 70, 90, 90, false, wxT("00 ZRCola") ) ); + m_gridPreview->SetDefaultCellFont( wxFont( 120, 70, 90, 90, false, wxT("00 ZRCola") ) ); m_gridPreview->SetDefaultCellAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); - sbSizerPreview->Add( m_gridPreview, 0, wxALIGN_CENTER|wxALL, 5 ); + m_gridPreview->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); + + sbSizerPreview->Add( m_gridPreview, 0, wxALL|wxEXPAND, 5 ); m_description = new wxTextCtrl( sbSizerPreview->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_CENTRE|wxTE_MULTILINE|wxTE_READONLY ); sbSizerPreview->Add( m_description, 1, wxALL|wxEXPAND, 5 ); - bSizerRight->Add( sbSizerPreview, 0, wxALL|wxEXPAND, 5 ); + bSizerRight->Add( sbSizerPreview, 70, wxALL|wxEXPAND, 5 ); wxStaticBoxSizer* sbSizerRelated; sbSizerRelated = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Re&lated") ), wxVERTICAL ); - m_gridRelated = new wxGrid( sbSizerRelated->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_gridRelated = new wxZRColaCharGrid( sbSizerRelated->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxSTATIC_BORDER ); // Grid - m_gridRelated->CreateGrid( 3, 6 ); + m_gridRelated->CreateGrid( 0, 0 ); m_gridRelated->EnableEditing( false ); - m_gridRelated->EnableGridLines( true ); + m_gridRelated->EnableGridLines( false ); m_gridRelated->EnableDragGridSize( false ); m_gridRelated->SetMargins( 0, 0 ); // Columns - m_gridRelated->SetColSize( 0, 35 ); - m_gridRelated->SetColSize( 1, 35 ); - m_gridRelated->SetColSize( 2, 35 ); - m_gridRelated->SetColSize( 3, 35 ); - m_gridRelated->SetColSize( 4, 35 ); - m_gridRelated->SetColSize( 5, 35 ); m_gridRelated->EnableDragColMove( false ); m_gridRelated->EnableDragColSize( false ); m_gridRelated->SetColLabelSize( 0 ); m_gridRelated->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Rows - m_gridRelated->SetRowSize( 0, 35 ); - m_gridRelated->SetRowSize( 1, 35 ); - m_gridRelated->SetRowSize( 2, 35 ); m_gridRelated->EnableDragRowSize( false ); m_gridRelated->SetRowLabelSize( 0 ); m_gridRelated->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); @@ -622,11 +582,11 @@ wxZRColaCharSelectBase::wxZRColaCharSelectBase( wxWindow* parent, wxWindowID id, // Cell Defaults m_gridRelated->SetDefaultCellFont( wxFont( 20, 70, 90, 90, false, wxT("00 ZRCola") ) ); - m_gridRelated->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); - sbSizerRelated->Add( m_gridRelated, 0, wxALIGN_CENTER|wxALL, 5 ); + m_gridRelated->SetDefaultCellAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + sbSizerRelated->Add( m_gridRelated, 1, wxALL|wxEXPAND, 5 ); - bSizerRight->Add( sbSizerRelated, 1, wxALL|wxEXPAND, 5 ); + bSizerRight->Add( sbSizerRelated, 30, wxALL|wxEXPAND, 5 ); bSizerColumns->Add( bSizerRight, 0, wxEXPAND, 5 ); @@ -650,22 +610,41 @@ wxZRColaCharSelectBase::wxZRColaCharSelectBase( wxWindow* parent, wxWindowID id, this->SetSizer( bSizerContent ); this->Layout(); bSizerContent->Fit( this ); + m_timerSearch.SetOwner( this, wxID_TIMER_SEARCH ); // Connect Events + this->Connect( wxEVT_IDLE, wxIdleEventHandler( wxZRColaCharSelectBase::OnIdle ) ); m_search->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxZRColaCharSelectBase::OnSearchText ), NULL, this ); + m_search->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( wxZRColaCharSelectBase::OnSearchEnter ), NULL, this ); + m_categories->Connect( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, wxCommandEventHandler( wxZRColaCharSelectBase::OnCategoriesToggle ), NULL, this ); + m_gridResults->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( wxZRColaCharSelectBase::OnResultCellDClick ), NULL, this ); m_gridResults->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( wxZRColaCharSelectBase::OnResultSelectCell ), NULL, this ); + m_gridResults->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( wxZRColaCharSelectBase::OnResultsKeyDown ), NULL, this ); + m_gridRecent->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( wxZRColaCharSelectBase::OnRecentCellDClick ), NULL, this ); m_gridRecent->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( wxZRColaCharSelectBase::OnRecentSelectCell ), NULL, this ); + m_gridRecent->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( wxZRColaCharSelectBase::OnRecentKeyDown ), NULL, this ); m_unicode->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxZRColaCharSelectBase::OnUnicodeText ), NULL, this ); m_gridRelated->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( wxZRColaCharSelectBase::OnRelatedSelectCell ), NULL, this ); + m_sdbSizerButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( wxZRColaCharSelectBase::OnOKButtonClick ), NULL, this ); + this->Connect( wxID_TIMER_SEARCH, wxEVT_TIMER, wxTimerEventHandler( wxZRColaCharSelectBase::OnSearchTimer ) ); } wxZRColaCharSelectBase::~wxZRColaCharSelectBase() { // Disconnect Events + this->Disconnect( wxEVT_IDLE, wxIdleEventHandler( wxZRColaCharSelectBase::OnIdle ) ); m_search->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxZRColaCharSelectBase::OnSearchText ), NULL, this ); + m_search->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( wxZRColaCharSelectBase::OnSearchEnter ), NULL, this ); + m_categories->Disconnect( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, wxCommandEventHandler( wxZRColaCharSelectBase::OnCategoriesToggle ), NULL, this ); + m_gridResults->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( wxZRColaCharSelectBase::OnResultCellDClick ), NULL, this ); m_gridResults->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( wxZRColaCharSelectBase::OnResultSelectCell ), NULL, this ); + m_gridResults->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( wxZRColaCharSelectBase::OnResultsKeyDown ), NULL, this ); + m_gridRecent->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( wxZRColaCharSelectBase::OnRecentCellDClick ), NULL, this ); m_gridRecent->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( wxZRColaCharSelectBase::OnRecentSelectCell ), NULL, this ); + m_gridRecent->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( wxZRColaCharSelectBase::OnRecentKeyDown ), NULL, this ); m_unicode->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxZRColaCharSelectBase::OnUnicodeText ), NULL, this ); m_gridRelated->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( wxZRColaCharSelectBase::OnRelatedSelectCell ), NULL, this ); + m_sdbSizerButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( wxZRColaCharSelectBase::OnOKButtonClick ), NULL, this ); + this->Disconnect( wxID_TIMER_SEARCH, wxEVT_TIMER, wxTimerEventHandler( wxZRColaCharSelectBase::OnSearchTimer ) ); } diff --git a/ZRCola/zrcolagui.h b/ZRCola/zrcolagui.h index b594f8d..e0c6251 100644 --- a/ZRCola/zrcolagui.h +++ b/ZRCola/zrcolagui.h @@ -35,11 +35,11 @@ class wxZRColaComposerPanel; #include #include #include +#include #include #include #include #include -#include #include #include @@ -56,7 +56,7 @@ class wxZRColaFrameBase : public wxFrame enum { wxID_AUTOSTART = 1000, - wxID_INSERT_CHARACTER, + wxID_CHARACTER_SELECTOR, wxID_SEND_COMPOSED, wxID_SEND_DECOMPOSED, wxID_SEND_ABORT, @@ -77,6 +77,7 @@ class wxZRColaFrameBase : public wxFrame wxAuiToolBarItem* m_toolEditCopy; wxAuiToolBarItem* m_toolEditPaste; wxAuiToolBar* m_toolbarCompose; + wxAuiToolBarItem* m_toolCharSelect; wxAuiToolBarItem* m_toolSendComposed; wxAuiToolBarItem* m_toolSendDecomposed; wxChoice* m_toolDecompLanguage; @@ -107,6 +108,11 @@ class wxZRColaComposerPanelBase : public wxPanel private: protected: + enum + { + wxID_TIMER_SAVE = 1000 + }; + wxSplitterWindow* m_splitterDecomposed; wxPanel* m_panelDecomposedEdit; wxPanel* m_panelDecomposedHex; @@ -115,6 +121,7 @@ class wxZRColaComposerPanelBase : public wxPanel wxPanel* m_panelComposedEdit; wxPanel* m_panelComposedHex; wxTextCtrl* m_composedHex; + wxTimer m_timerSave; // Virtual event handlers, overide them in your derived class virtual void OnDecomposedPaint( wxPaintEvent& event ) { event.Skip(); } @@ -123,6 +130,7 @@ class wxZRColaComposerPanelBase : public wxPanel virtual void OnComposedPaint( wxPaintEvent& event ) { event.Skip(); } virtual void OnComposedText( wxCommandEvent& event ) { event.Skip(); } virtual void OnComposedHexPaint( wxPaintEvent& event ) { event.Skip(); } + virtual void OnSaveTimer( wxTimerEvent& event ) { event.Skip(); } public: @@ -178,29 +186,43 @@ class wxZRColaCharSelectBase : public wxDialog private: protected: + enum + { + wxID_TIMER_SEARCH = 1000 + }; + wxSearchCtrl* m_search; wxCheckListBox* m_categories; - wxGrid* m_gridResults; - wxGrid* m_gridRecent; + wxZRColaCharGrid* m_gridResults; + wxZRColaCharGrid* m_gridRecent; wxStaticText* m_labelUnicode; wxTextCtrl* m_unicode; wxGrid* m_gridPreview; wxTextCtrl* m_description; - wxGrid* m_gridRelated; + wxZRColaCharGrid* m_gridRelated; wxStdDialogButtonSizer* m_sdbSizerButtons; wxButton* m_sdbSizerButtonsOK; wxButton* m_sdbSizerButtonsCancel; + wxTimer m_timerSearch; // Virtual event handlers, overide them in your derived class + virtual void OnIdle( wxIdleEvent& event ) { event.Skip(); } virtual void OnSearchText( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSearchEnter( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCategoriesToggle( wxCommandEvent& event ) { event.Skip(); } + virtual void OnResultCellDClick( wxGridEvent& event ) { event.Skip(); } virtual void OnResultSelectCell( wxGridEvent& event ) { event.Skip(); } + virtual void OnResultsKeyDown( wxKeyEvent& event ) { event.Skip(); } + virtual void OnRecentCellDClick( wxGridEvent& event ) { event.Skip(); } virtual void OnRecentSelectCell( wxGridEvent& event ) { event.Skip(); } + virtual void OnRecentKeyDown( wxKeyEvent& event ) { event.Skip(); } virtual void OnUnicodeText( wxCommandEvent& event ) { event.Skip(); } virtual void OnRelatedSelectCell( wxGridEvent& event ) { event.Skip(); } + virtual void OnOKButtonClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSearchTimer( wxTimerEvent& event ) { event.Skip(); } public: - wxString m_unicodeValid; wxZRColaCharSelectBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Character Selector"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE, const wxString& name = wxT("ZRColaCharSelect") ); ~wxZRColaCharSelectBase(); diff --git a/ZRColaCompile/dbsource.cpp b/ZRColaCompile/dbsource.cpp index 5ccbb39..3cde67f 100644 --- a/ZRColaCompile/dbsource.cpp +++ b/ZRColaCompile/dbsource.cpp @@ -20,6 +20,94 @@ #include "stdafx.h" + +bool ZRCola::DBSource::character_desc_idx::add_keywords(const wchar_t *str, wchar_t chr, size_t sub) +{ + wxASSERT_MSG(str, wxT("string is NULL")); + + while (*str) { + // Skip white space. + for (;;) { + if (*str == 0) + return true; + else if (!iswspace(*str)) + break; + else + str++; + } + + // Get term. + std::wstring term; + if (*str == L'"') { + const wchar_t *str_end = ++str; + for (;;) { + if (*str_end == 0) { + term.assign(str, str_end); + break; + } else if (*str_end == L'"') { + term.assign(str, str_end); + str_end++; + break; + } else + str_end++; + } + str = str_end; + } else { + const wchar_t *str_end = str + 1; + for (; *str_end && !iswspace(*str_end); str_end++); + term.assign(str, str_end); + str = str_end; + } + + if (!term.empty()) { + std::transform(term.begin(), term.end(), term.begin(), std::towlower); + if (sub) { + std::wstring::size_type j_end = term.size(); + if (j_end >= sub) { + // Insert all keyword substrings "sub" or more characters long. + for (std::wstring::size_type i = 0, i_end = j_end - sub; i < i_end; ++i) { + for (std::wstring::size_type j = i + sub; j < j_end; ++j) + add_keyword(term.substr(i, j - i), chr); + } + } + } else { + // Insert exact keyword only. + add_keyword(term, chr); + } + } + } + + return true; +} + + +void ZRCola::DBSource::character_desc_idx::save(ZRCola::textindex &idx) const +{ + idx .clear(); + idx.keys .clear(); + idx.values.clear(); + + // Pre-allocate memory. + std::vector::size_type size_keys = 0; + std::vector::size_type size_values = 0; + for (const_iterator i = cbegin(), i_end = cend(); i != i_end; ++i) { + size_keys += i->first.size(); + size_values += i->second.size(); + } + idx .reserve(size() ); + idx.keys .reserve(size_keys ); + idx.values.reserve(size_values); + + // Convert the index. + for (const_iterator i = cbegin(), i_end = cend(); i != i_end; ++i) { + ZRCola::mappair_t p = { idx.keys.size(), idx.values.size() }; + idx.push_back(p); + idx.keys.insert(idx.keys.end(), i->first.cbegin(), i->first.cend()); + idx.values.insert(idx.values.end(), i->second.cbegin(), i->second.cend()); + } +} + + ZRCola::DBSource::DBSource() { } @@ -348,14 +436,14 @@ bool ZRCola::DBSource::GetChrCat(const ATL::CComPtr& f, chrcatid_t& cc _ftprintf(stderr, wxT("%s: error ZCC0111: Syntax error in \"%.*ls\" field (\"%.*ls\"). Character category ID must contain ASCII characters only.\n"), m_filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v)); return false; } - cc[i] = (char)c; + cc.data[i] = (char)c; } else - cc[i] = 0; + cc.data[i] = 0; } else break; } } else - memset(cc, 0, sizeof(cc)); + memset(cc.data, 0, sizeof(cc)); return true; } diff --git a/ZRColaCompile/dbsource.h b/ZRColaCompile/dbsource.h index 15fbf0d..28f2f47 100644 --- a/ZRColaCompile/dbsource.h +++ b/ZRColaCompile/dbsource.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -112,6 +113,61 @@ namespace ZRCola { }; + /// + /// Character description index key comparator + /// + struct character_desc_idx_less : public std::binary_function + { + inline bool operator()(const std::wstring& _Left, const std::wstring& _Right) const + { + size_t + _Left_len = _Left .size(), + _Right_len = _Right.size(); + + int r = _wcsncoll(_Left.c_str(), _Right.c_str(), std::min(_Left_len, _Right_len)); + if (r != 0 ) return r < 0; + else if (_Left_len < _Right_len) return true; + + return false; + } + }; + + + /// + /// Character description index + /// + class character_desc_idx : public std::map, character_desc_idx_less> + { + public: + bool add_keywords(const wchar_t *str, wchar_t chr, size_t sub = 0); + + void save(ZRCola::textindex &idx) const; + + protected: + inline void add_keyword(const std::wstring &term, wchar_t chr) + { + iterator idx = find(term); + if (idx == end()) { + // New keyword. + insert(std::make_pair(term, std::vector(1, chr))); + } else { + // Append to existing keyword. + std::vector &val = idx->second; + for (std::vector::iterator i = val.begin(), i_end = val.end(); ; ++i) { + if (i == i_end) { + // End-of-values reached. Append character. + val.push_back(chr); + break; + } else if (*i == chr) { + // Character already among the values. + break; + } + } + } + } + }; + + /// /// Character category /// @@ -176,6 +232,19 @@ namespace ZRCola { } + /// + /// Splits string to individual keywords + /// + /// \param[in ] str String + /// \param[out] keywords Array of keywords + /// + /// \returns + /// - true when successful + /// - false otherwise + /// + static bool GetKeywords(const wchar_t *str, std::vector< std::wstring > &keywords); + + /// /// Gets boolean from ZRCola.zrc database /// diff --git a/ZRColaCompile/main.cpp b/ZRColaCompile/main.cpp index b00d914..838d1dd 100644 --- a/ZRColaCompile/main.cpp +++ b/ZRColaCompile/main.cpp @@ -20,383 +20,6 @@ #include "stdafx.h" -/// -/// Writes translation database to a stream -/// -/// \param[in] stream Output stream -/// \param[in] db Translation database -/// -/// \returns The stream \p stream -/// -inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::translation_db &db) -{ - assert(db.idxComp.size() == db.idxDecomp.size()); - - unsigned __int32 count; - - // Write index count. - ZRCola::translation_db::indexComp::size_type trans_count = db.idxComp.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (trans_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)trans_count; - stream.write((const char*)&count, sizeof(count)); - - // Write composition index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxComp.data(), sizeof(unsigned __int32)*count); - - // Write decomposition index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxDecomp.data(), sizeof(unsigned __int32)*count); - - // Write data count. - std::vector::size_type data_count = db.data.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (data_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)data_count; - stream.write((const char*)&count, sizeof(count)); - - // Write data. - if (stream.fail()) return stream; - stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); - - return stream; -} - - -/// -/// Writes key sequence database to a stream -/// -/// \param[in] stream Output stream -/// \param[in] db Key sequence database -/// -/// \returns The stream \p stream -/// -inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::keyseq_db &db) -{ - assert(db.idxChr.size() == db.idxKey.size()); - - unsigned __int32 count; - - // Write index count. - ZRCola::keyseq_db::indexChr::size_type ks_count = db.idxChr.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (ks_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)ks_count; - stream.write((const char*)&count, sizeof(count)); - - // Write character index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxChr.data(), sizeof(unsigned __int32)*count); - - // Write key index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxKey.data(), sizeof(unsigned __int32)*count); - - // Write data count. - std::vector::size_type data_count = db.data.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (data_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)data_count; - stream.write((const char*)&count, sizeof(count)); - - // Write data. - if (stream.fail()) return stream; - stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); - - return stream; -} - - -/// -/// Writes language database to a stream -/// -/// \param[in] stream Output stream -/// \param[in] db Language database -/// -/// \returns The stream \p stream -/// -inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::language_db &db) -{ - unsigned __int32 count; - - // Write index count. - ZRCola::language_db::indexLang::size_type lang_count = db.idxLng.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (lang_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)lang_count; - stream.write((const char*)&count, sizeof(count)); - - // Write language index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxLng.data(), sizeof(unsigned __int32)*count); - - - // Write data count. - std::vector::size_type data_count = db.data.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (data_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)data_count; - stream.write((const char*)&count, sizeof(count)); - - // Write data. - if (stream.fail()) return stream; - stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); - - return stream; -} - - -/// -/// Writes language character database to a stream -/// -/// \param[in] stream Output stream -/// \param[in] db Language character database -/// -/// \returns The stream \p stream -/// -inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::langchar_db &db) -{ -#ifdef ZRCOLA_LANGCHAR_LANG_IDX - assert(db.idxChr.size() == db.idxLng.size()); -#endif - - unsigned __int32 count; - - // Write index count. - ZRCola::langchar_db::indexChar::size_type lc_count = db.idxChr.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (lc_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)lc_count; - stream.write((const char*)&count, sizeof(count)); - - // Write character index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxChr.data(), sizeof(unsigned __int32)*count); - -#ifdef ZRCOLA_LANGCHAR_LANG_IDX - // Write language index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxLng.data(), sizeof(unsigned __int32)*count); -#endif - - // Write data count. - std::vector::size_type data_count = db.data.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (data_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)data_count; - stream.write((const char*)&count, sizeof(count)); - - // Write data. - if (stream.fail()) return stream; - stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); - - return stream; -} - - -/// -/// Writes character group database to a stream -/// -/// \param[in] stream Output stream -/// \param[in] db Character group database -/// -/// \returns The stream \p stream -/// -inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::chrgrp_db &db) -{ - unsigned __int32 count; - - // Write index count. - ZRCola::keyseq_db::indexChr::size_type ks_count = db.idxRnk.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (ks_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)ks_count; - stream.write((const char*)&count, sizeof(count)); - - // Write rank index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxRnk.data(), sizeof(unsigned __int32)*count); - - // Write data count. - std::vector::size_type data_count = db.data.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (data_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)data_count; - stream.write((const char*)&count, sizeof(count)); - - // Write data. - if (stream.fail()) return stream; - stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); - - return stream; -} - - -/// -/// Writes character database to a stream -/// -/// \param[in] stream Output stream -/// \param[in] db Character database -/// -/// \returns The stream \p stream -/// -inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::character_db &db) -{ - unsigned __int32 count; - - // Write index count. - ZRCola::keyseq_db::indexChr::size_type ks_count = db.idxChr.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (ks_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)ks_count; - stream.write((const char*)&count, sizeof(count)); - - // Write character index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxChr.data(), sizeof(unsigned __int32)*count); - - // Write data count. - std::vector::size_type data_count = db.data.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (data_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)data_count; - stream.write((const char*)&count, sizeof(count)); - - // Write data. - if (stream.fail()) return stream; - stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); - - return stream; -} - - -/// -/// Writes character category database to a stream -/// -/// \param[in] stream Output stream -/// \param[in] db Character category database -/// -/// \returns The stream \p stream -/// -inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::chrcat_db &db) -{ - unsigned __int32 count; - - // Write index count. - ZRCola::keyseq_db::indexChr::size_type ks_count = db.idxChrCat.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (ks_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)ks_count; - stream.write((const char*)&count, sizeof(count)); - - // Write character category index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxChrCat.data(), sizeof(unsigned __int32)*count); - - // Write rank index. - if (stream.fail()) return stream; - stream.write((const char*)db.idxRnk.data(), sizeof(unsigned __int32)*count); - - // Write data count. - std::vector::size_type data_count = db.data.size(); -#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) - // 4G check - if (data_count > 0xffffffff) { - stream.setstate(std::ios_base::failbit); - return stream; - } -#endif - if (stream.fail()) return stream; - count = (unsigned __int32)data_count; - stream.write((const char*)&count, sizeof(count)); - - // Write data. - if (stream.fail()) return stream; - stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); - - return stream; -} - - /// /// Main function /// @@ -768,6 +391,7 @@ int _tmain(int argc, _TCHAR *argv[]) if (count < 0xffffffff) { // 4G check (-1 is reserved for error condition) ZRCola::DBSource::character chr; ZRCola::character_db db; + ZRCola::DBSource::character_desc_idx idxChrDsc, idxChrDscSub; // Preallocate memory. db.idxChr.reserve(count); @@ -781,7 +405,7 @@ int _tmain(int argc, _TCHAR *argv[]) unsigned __int32 idx = db.data.size(); db.data.push_back((unsigned __int16)chr.chr); for (std::wstring::size_type i = 0; i < sizeof(ZRCola::chrcatid_t)/sizeof(unsigned __int16); i++) - db.data.push_back(((const unsigned __int16*)chr.cat)[i]); + db.data.push_back(((const unsigned __int16*)chr.cat.data)[i]); std::wstring::size_type n_desc = chr.desc.length(); wxASSERT_MSG(n_desc <= 0xffff, wxT("character description too long")); db.data.push_back((unsigned __int16)n_desc); @@ -793,6 +417,12 @@ int _tmain(int argc, _TCHAR *argv[]) for (std::wstring::size_type i = 0; i < n_rel; i++) db.data.push_back(chr.rel[i]); db.idxChr.push_back(idx); + + // Add description (and keywords) to index. + idxChrDsc .add_keywords(chr.desc .c_str(), chr.chr, 0); + idxChrDsc .add_keywords(chr.keywords.c_str(), chr.chr, 0); + idxChrDscSub.add_keywords(chr.desc .c_str(), chr.chr, 3); + idxChrDscSub.add_keywords(chr.keywords.c_str(), chr.chr, 3); } else has_errors = true; @@ -802,6 +432,10 @@ int _tmain(int argc, _TCHAR *argv[]) // Sort indices. db.idxChr.sort(); + // Save text indices. + idxChrDsc .save(db.idxDsc ); + idxChrDscSub.save(db.idxDscSub); + // Write characters to file. dst << ZRCola::character_rec(db); } else { @@ -835,7 +469,7 @@ int _tmain(int argc, _TCHAR *argv[]) // Add character category to index and data. unsigned __int32 idx = db.data.size(); for (std::wstring::size_type i = 0; i < sizeof(ZRCola::chrcatid_t)/sizeof(unsigned __int16); i++) - db.data.push_back(((const unsigned __int16*)cc.id)[i]); + db.data.push_back(((const unsigned __int16*)cc.id.data)[i]); wxASSERT_MSG((int)0xffff8000 <= cc.rank && cc.rank <= (int)0x00007fff, wxT("character category rank out of bounds")); db.data.push_back((unsigned __int16)cc.rank); std::wstring::size_type n_name = cc.name.length(); diff --git a/ZRColaCompile/stdafx.h b/ZRColaCompile/stdafx.h index 186fe8f..9d54a3a 100644 --- a/ZRColaCompile/stdafx.h +++ b/ZRColaCompile/stdafx.h @@ -48,6 +48,8 @@ #include +#include #include +#include #include #include diff --git a/lib/libZRCola/build/libZRCola.vcxproj b/lib/libZRCola/build/libZRCola.vcxproj index e940d35..c4d15b2 100644 --- a/lib/libZRCola/build/libZRCola.vcxproj +++ b/lib/libZRCola/build/libZRCola.vcxproj @@ -19,6 +19,7 @@ + diff --git a/lib/libZRCola/build/libZRCola.vcxproj.filters b/lib/libZRCola/build/libZRCola.vcxproj.filters index f87aee2..3bce8e1 100644 --- a/lib/libZRCola/build/libZRCola.vcxproj.filters +++ b/lib/libZRCola/build/libZRCola.vcxproj.filters @@ -30,6 +30,9 @@ Source Files + + Source Files + diff --git a/lib/libZRCola/include/zrcola/character.h b/lib/libZRCola/include/zrcola/character.h index d44b566..95a3b4d 100644 --- a/lib/libZRCola/include/zrcola/character.h +++ b/lib/libZRCola/include/zrcola/character.h @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include @@ -37,7 +39,55 @@ namespace ZRCola { /// Character category ID type /// Two letter abbreviation, non-terminated /// - typedef char chrcatid_t[2]; + struct chrcatid_t { + char data[2]; + + inline chrcatid_t& operator=(const chrcatid_t &src) + { + data[0] = src.data[0]; + data[1] = src.data[1]; + return *this; + } + }; + + + /// + /// Compares two character category IDs + /// + /// \param[in] a First character category ID + /// \param[in] b Second character category ID + /// + /// \returns + /// - true when \p a < \p b + /// - false otherwise + /// + inline bool operator<(const chrcatid_t& a, const chrcatid_t& b) + { + if (a.data[0] < b.data[0]) return true; + else if (a.data[0] > b.data[0]) return false; + else if (a.data[1] < b.data[1]) return true; + else return false; + } + + + /// + /// Compares two character category IDs + /// + /// \param[in] a First character category ID + /// \param[in] b Second character category ID + /// + /// \returns + /// - true when \p a > \p b + /// - false otherwise + /// + inline bool operator>(const chrcatid_t& a, const chrcatid_t& b) + { + if (a.data[0] > b.data[0]) return true; + else if (a.data[0] < b.data[0]) return false; + else if (a.data[1] > b.data[1]) return true; + else return false; + } + /// /// Character Database @@ -91,13 +141,17 @@ namespace ZRCola { } } idxChr; ///< Character index - std::vector data; ///< Character data + textindex idxDsc; ///< Description index + textindex idxDscSub; ///< Description index (sub-terms) + std::vector data; ///< Character data public: /// /// Constructs the database /// inline character_db() : idxChr(data) {} + + void search_by_desc(_In_z_ const wchar_t *str, _Inout_ std::map &hits, _Inout_ std::map &hits_sub) const; }; @@ -148,10 +202,9 @@ namespace ZRCola { /// virtual int compare(_In_ const chrcat &a, _In_ const chrcat &b) const { - int r = memcmp(a.id, b.id, sizeof(chrcatid_t)); - if (r != 0) return r; - - return 0; + if (a.id < b.id) return -1; + else if (a.id < b.id) return 1; + else return 0; } } idxChrCat; ///< Character category index @@ -233,31 +286,118 @@ const ZRCola::recordid_t stdex::idrec::record>(_In_ std::istream& stream, _Out_ ZRCola::character_db &db) { - unsigned __int32 count; - - // Read index count. - stream.read((char*)&count, sizeof(count)); + // Read character index. + stream >> db.idxChr; if (!stream.good()) return stream; - // Read character index. - db.idxChr.resize(count); - stream.read((char*)db.idxChr.data(), sizeof(unsigned __int32)*count); + // Read description index. + stream >> db.idxDsc; + if (!stream.good()) return stream; + + // Read sub-term description index. + stream >> db.idxDscSub; if (!stream.good()) return stream; // Read data count. + unsigned __int32 count; stream.read((char*)&count, sizeof(count)); if (!stream.good()) return stream; - // Read data. - db.data.resize(count); - stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + if (count) { + // Read data. + db.data.resize(count); + stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + } else + db.data.clear(); + + return stream; +} + + +/// +/// Writes character database to a stream +/// +/// \param[in] stream Output stream +/// \param[in] db Character database +/// +/// \returns The stream \p stream +/// +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::character_db &db) +{ + // Write character index. + if (stream.fail()) return stream; + stream << db.idxChr; + + // Write description index. + if (!stream.good()) return stream; + stream << db.idxDsc; + + // Write sub-term description index. + if (!stream.good()) return stream; + stream << db.idxDscSub; + + // Write data count. + std::vector::size_type data_count = db.data.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (data_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)data_count; + stream.write((const char*)&count, sizeof(count)); + + // Write data. + if (stream.fail()) return stream; + stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); + + return stream; +} + + +/// +/// Writes character category database to a stream +/// +/// \param[in] stream Output stream +/// \param[in] db Character category database +/// +/// \returns The stream \p stream +/// +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::chrcat_db &db) +{ + // Write character category index. + if (stream.fail()) return stream; + stream << db.idxChrCat; + + // Write rank index. + if (stream.fail()) return stream; + stream << db.idxRnk; + + // Write data count. + std::vector::size_type data_count = db.data.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (data_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)data_count; + stream.write((const char*)&count, sizeof(count)); + + // Write data. + if (stream.fail()) return stream; + stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); return stream; } @@ -266,36 +406,32 @@ inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::charac /// /// Reads character category database from a stream /// -/// \param[in] stream Input stream +/// \param[in ] stream Input stream /// \param[out] db Character category database /// /// \returns The stream \p stream /// inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::chrcat_db &db) { - unsigned __int32 count; - - // Read index count. - stream.read((char*)&count, sizeof(count)); - if (!stream.good()) return stream; - // Read character category index. - db.idxChrCat.resize(count); - stream.read((char*)db.idxChrCat.data(), sizeof(unsigned __int32)*count); + stream >> db.idxChrCat; if (!stream.good()) return stream; // Read rank index. - db.idxRnk.resize(count); - stream.read((char*)db.idxRnk.data(), sizeof(unsigned __int32)*count); + stream >> db.idxRnk; if (!stream.good()) return stream; // Read data count. + unsigned __int32 count; stream.read((char*)&count, sizeof(count)); if (!stream.good()) return stream; - // Read data. - db.data.resize(count); - stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + if (count) { + // Read data. + db.data.resize(count); + stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + } else + db.data.clear(); return stream; } diff --git a/lib/libZRCola/include/zrcola/common.h b/lib/libZRCola/include/zrcola/common.h index ea93f24..30f487b 100644 --- a/lib/libZRCola/include/zrcola/common.h +++ b/lib/libZRCola/include/zrcola/common.h @@ -19,6 +19,9 @@ #pragma once +#include +#include +#include #include #ifdef _WIN32 #include @@ -60,6 +63,20 @@ namespace ZRCola { typedef unsigned __int32 recordsize_t; + /// + /// Key-value index pair for mappings + /// +#pragma pack(push) +#pragma pack(2) + template + struct mappair_t + { + T idx_key; ///< Index of key + T idx_val; ///< Index of value + }; +#pragma pack(pop) + + /// /// Language ID type /// Three letter abbreviation, zero terminated @@ -207,7 +224,7 @@ namespace ZRCola { for (start = 0, end = size(); start < end; ) { size_type m = (start + end) / 2; int r = compare(el, at(m)); - if (r < 0) end = m; + if (r < 0) end = m; else if (r > 0) start = m + 1; else { // Narrow the search area on the left to start at the first element in the run. @@ -240,6 +257,75 @@ namespace ZRCola { }; + /// + /// Memory text index + /// + template + class textindex : public std::vector< mappair_t > + { + public: + typedef std::vector< mappair_t > base_t; + std::vector keys; ///< Key data + std::vector values; ///< Index values + + public: + /// + /// Constructs the index + /// + textindex() {} + + + /// + /// Finds data for given key + /// + /// \param[in ] key Pointer to key + /// \param[in ] key_len Count of \p key elements + /// \param[out] val Pointer to receive pointer to key's values + /// \param[out] val_len Pointer to receive count of \p val elements + /// + /// \returns + /// - \c true if found + /// - \c false otherwise + /// + bool find(_In_count_(key_len) const T_key *key, _In_ size_t key_len, _Out_ const T_val **val, _Out_ size_t *val_len) const + { + for (size_type start = 0, end = size(); start < end; ) { + size_type m = (start + end) / 2; + int r = compare(key, key_len, m); + if (r < 0) end = m; + else if (r > 0) start = m + 1; + else { + // Get values at position m. + size_t start = base_t::at(m ).idx_val; + *val_len = (m < size() ? base_t::at(m + 1).idx_val : values.size()) - start; + *val = &values.at(start); + return true; + } + } + + return false; + } + + protected: + inline int compare(_In_count_(key_len) const T_key *key, _In_ size_t key_len, size_type pos) const + { + // Get key at position pos. + size_t + start = base_t::at(pos ).idx_key, + key2_len = (pos < size() ? base_t::at(pos + 1).idx_key : keys.size()) - start; + std::vector::const_pointer key2 = &keys.at(start); + + // Compare keys. + int r = memcmp(key, key2, sizeof(T_key)*std::min(key_len, key2_len)); + if (r != 0 ) return r; + else if (key_len < key2_len) return -1; + else if (key_len > key2_len) return 1; + + return 0; + } + }; + + /// /// Source-destination index transformation mapping /// @@ -292,4 +378,184 @@ namespace ZRCola { }; }; + +/// +/// Writes index to a stream +/// +/// \param[in] stream Output stream +/// \param[in] idx Index +/// +/// \returns The stream \p stream +/// +template +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::index &idx) +{ + // Write index count. + ZRCola::index::size_type idx_count = idx.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (idx_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)idx_count; + stream.write((const char*)&count, sizeof(count)); + + // Write index data. + if (stream.fail()) return stream; + stream.write((const char*)idx.data(), sizeof(T_idx)*count); + + return stream; +} + + +/// +/// Reads index from a stream +/// +/// \param[in] stream Input stream +/// \param[out] idx Index +/// +/// \returns The stream \p stream +/// +template +inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::index &idx) +{ + unsigned __int32 count; + + // Read index count. + stream.read((char*)&count, sizeof(count)); + if (!stream.good()) return stream; + + if (count) { + // Read index data. + idx.resize(count); + stream.read((char*)idx.data(), sizeof(T_idx)*count); + } else + idx.clear(); + + return stream; +} + + +/// +/// Writes text index to a stream +/// +/// \param[in] stream Output stream +/// \param[in] idx Text index +/// +/// \returns The stream \p stream +/// +template +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::textindex &idx) +{ + unsigned __int32 count; + + // Write index count. + ZRCola::textindex::size_type idx_count = idx.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (idx_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + count = (unsigned __int32)idx_count; + stream.write((const char*)&count, sizeof(count)); + + // Write index data. + if (stream.fail()) return stream; + stream.write((const char*)idx.data(), sizeof(ZRCola::textindex::value_type)*count); + + // Write key count. + std::vector::size_type key_count = idx.keys.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (idx_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + count = (unsigned __int32)key_count; + stream.write((const char*)&count, sizeof(count)); + + // Write key data. + if (stream.fail()) return stream; + stream.write((const char*)idx.keys.data(), sizeof(std::vector::value_type)*count); + + // Write value count. + std::vector::size_type value_count = idx.values.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (idx_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + count = (unsigned __int32)value_count; + stream.write((const char*)&count, sizeof(count)); + + // Write value data. + if (stream.fail()) return stream; + stream.write((const char*)idx.values.data(), sizeof(std::vector::value_type)*count); + + return stream; +} + + +/// +/// Reads text index from a stream +/// +/// \param[in] stream Input stream +/// \param[out] idx Text index +/// +/// \returns The stream \p stream +/// +template +inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::textindex &idx) +{ + unsigned __int32 count; + + // Read text index count. + stream.read((char*)&count, sizeof(count)); + if (!stream.good()) return stream; + + if (count) { + // Read text index. + idx.resize(count); + stream.read((char*)idx.data(), sizeof(ZRCola::textindex::value_type)*count); + if (!stream.good()) return stream; + } else + idx.clear(); + + // Read keys count. + stream.read((char*)&count, sizeof(count)); + if (!stream.good()) return stream; + + if (count) { + // Read keys. + idx.keys.resize(count); + stream.read((char*)idx.keys.data(), sizeof(std::vector::value_type)*count); + if (!stream.good()) return stream; + } else + idx.keys.clear(); + + // Read value count. + stream.read((char*)&count, sizeof(count)); + if (!stream.good()) return stream; + + if (count) { + // Read values. + idx.values.resize(count); + stream.read((char*)idx.values.data(), sizeof(std::vector::value_type)*count); + } else + idx.values.clear(); + + return stream; +} + #pragma warning(pop) diff --git a/lib/libZRCola/include/zrcola/language.h b/lib/libZRCola/include/zrcola/language.h index 29044c7..e5e5fec 100644 --- a/lib/libZRCola/include/zrcola/language.h +++ b/lib/libZRCola/include/zrcola/language.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -258,41 +259,113 @@ const ZRCola::recordid_t stdex::idrec::record::id = *(ZRCola::recordid_t*)"LNG"; +/// +/// Writes language character database to a stream +/// +/// \param[in] stream Output stream +/// \param[in] db Language character database +/// +/// \returns The stream \p stream +/// +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::langchar_db &db) +{ + // Write character index. + if (stream.fail()) return stream; + stream << db.idxChr; + +#ifdef ZRCOLA_LANGCHAR_LANG_IDX + // Write language index. + if (stream.fail()) return stream; + stream << db.idxLng; +#endif + + // Write data count. + std::vector::size_type data_count = db.data.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (data_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)data_count; + stream.write((const char*)&count, sizeof(count)); + + // Write data. + if (stream.fail()) return stream; + stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); + + return stream; +} + + /// /// Reads language character database from a stream /// -/// \param[in] stream Input stream +/// \param[in ] stream Input stream /// \param[out] db Language character database /// /// \returns The stream \p stream /// inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::langchar_db &db) { - unsigned __int32 count; - - // Read index count. - stream.read((char*)&count, sizeof(count)); - if (!stream.good()) return stream; - // Read character index. - db.idxChr.resize(count); - stream.read((char*)db.idxChr.data(), sizeof(unsigned __int32)*count); + stream >> db.idxChr; if (!stream.good()) return stream; #ifdef ZRCOLA_LANGCHAR_LANG_IDX // Read language index. - db.idxLng.resize(count); - stream.read((char*)db.idxLng.data(), sizeof(unsigned __int32)*count); + stream >> db.idxLng; if (!stream.good()) return stream; #endif // Read data count. + unsigned __int32 count; stream.read((char*)&count, sizeof(count)); if (!stream.good()) return stream; - // Read data. - db.data.resize(count); - stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + if (count) { + // Read data. + db.data.resize(count); + stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + } else + db.data.clear(); + + return stream; +} + + +/// +/// Writes language database to a stream +/// +/// \param[in] stream Output stream +/// \param[in] db Language database +/// +/// \returns The stream \p stream +/// +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::language_db &db) +{ + // Write language index. + if (stream.fail()) return stream; + stream << db.idxLng; + + // Write data count. + std::vector::size_type data_count = db.data.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (data_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)data_count; + stream.write((const char*)&count, sizeof(count)); + + // Write data. + if (stream.fail()) return stream; + stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); return stream; } @@ -301,31 +374,28 @@ inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::langch /// /// Reads language database from a stream /// -/// \param[in] stream Input stream +/// \param[in ] stream Input stream /// \param[out] db Language database /// /// \returns The stream \p stream /// inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::language_db &db) { - unsigned __int32 count; - - // Read index count. - stream.read((char*)&count, sizeof(count)); - if (!stream.good()) return stream; - // Read language index. - db.idxLng.resize(count); - stream.read((char*)db.idxLng.data(), sizeof(unsigned __int32)*count); + stream >> db.idxLng; if (!stream.good()) return stream; // Read data count. + unsigned __int32 count; stream.read((char*)&count, sizeof(count)); if (!stream.good()) return stream; - // Read data. - db.data.resize(count); - stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + if (count) { + // Read data. + db.data.resize(count); + stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + } else + db.data.clear(); return stream; } diff --git a/lib/libZRCola/include/zrcola/translate.h b/lib/libZRCola/include/zrcola/translate.h index 475dc92..a2d6c76 100644 --- a/lib/libZRCola/include/zrcola/translate.h +++ b/lib/libZRCola/include/zrcola/translate.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -247,39 +248,74 @@ namespace ZRCola { const ZRCola::recordid_t stdex::idrec::record::id = *(ZRCola::recordid_t*)"TRN"; +/// +/// Writes translation database to a stream +/// +/// \param[in] stream Output stream +/// \param[in] db Translation database +/// +/// \returns The stream \p stream +/// +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::translation_db &db) +{ + // Write composition index. + if (stream.fail()) return stream; + stream << db.idxComp; + + // Write decomposition index. + if (stream.fail()) return stream; + stream << db.idxDecomp; + + // Write data count. + std::vector::size_type data_count = db.data.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (data_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)data_count; + stream.write((const char*)&count, sizeof(count)); + + // Write data. + if (stream.fail()) return stream; + stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); + + return stream; +} + + /// /// Reads translation database from a stream /// -/// \param[in] stream Input stream +/// \param[in ] stream Input stream /// \param[out] db Translation database /// /// \returns The stream \p stream /// inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::translation_db &db) { - unsigned __int32 count; - - // Read index count. - stream.read((char*)&count, sizeof(count)); - if (!stream.good()) return stream; - // Read composition index. - db.idxComp.resize(count); - stream.read((char*)db.idxComp.data(), sizeof(unsigned __int32)*count); + stream >> db.idxComp; if (!stream.good()) return stream; // Read decomposition index. - db.idxDecomp.resize(count); - stream.read((char*)db.idxDecomp.data(), sizeof(unsigned __int32)*count); + stream >> db.idxDecomp; if (!stream.good()) return stream; // Read data count. + unsigned __int32 count; stream.read((char*)&count, sizeof(count)); if (!stream.good()) return stream; - // Read data. - db.data.resize(count); - stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + if (count) { + // Read data. + db.data.resize(count); + stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + } else + db.data.clear(); return stream; } diff --git a/lib/libZRCola/src/character.cpp b/lib/libZRCola/src/character.cpp new file mode 100644 index 0000000..f3b7604 --- /dev/null +++ b/lib/libZRCola/src/character.cpp @@ -0,0 +1,97 @@ +/* + Copyright 2015-2016 Amebis + + This file is part of ZRCola. + + ZRCola is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ZRCola is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ZRCola. If not, see . +*/ + +#include "stdafx.h" + + +void ZRCola::character_db::search_by_desc(_In_z_ const wchar_t *str, _Inout_ std::map &hits, _Inout_ std::map &hits_sub) const +{ + assert(str); + + while (*str) { + // Skip white space. + for (;;) { + if (*str == 0) + return; + else if (!iswspace(*str)) + break; + else + str++; + } + + // Get term. + std::wstring term; + if (*str == L'"') { + const wchar_t *str_end = ++str; + for (;;) { + if (*str_end == 0) { + term.assign(str, str_end); + break; + } else if (*str_end == L'"') { + term.assign(str, str_end); + str_end++; + break; + } else + str_end++; + } + str = str_end; + } else { + const wchar_t *str_end = str + 1; + for (; *str_end && !iswspace(*str_end); str_end++); + term.assign(str, str_end); + str = str_end; + } + + if (!term.empty()) { + // Find the term. + std::transform(term.begin(), term.end(), term.begin(), std::towlower); + + const wchar_t *data; + size_t len; + + if (idxDsc.find(term.c_str(), term.size(), &data, &len)) { + // The term was found. + for (size_t i = 0; i < len; i++) { + std::map::iterator idx = hits.find(data[i]); + if (idx == hits.end()) { + // New character. + hits.insert(std::make_pair(data[i], 1)); + } else { + // Increment existing character. + idx->second++; + } + } + } + + if (idxDscSub.find(term.c_str(), term.size(), &data, &len)) { + // The term was found in the sub-term index. + for (size_t i = 0; i < len; i++) { + std::map::iterator idx = hits_sub.find(data[i]); + if (idx == hits_sub.end()) { + // New character. + hits_sub.insert(std::make_pair(data[i], 1)); + } else { + // Increment existing character. + idx->second++; + } + } + } + } + } +} diff --git a/lib/libZRCola/src/stdafx.h b/lib/libZRCola/src/stdafx.h index f773d3d..9a338c4 100644 --- a/lib/libZRCola/src/stdafx.h +++ b/lib/libZRCola/src/stdafx.h @@ -27,3 +27,6 @@ #include "../include/zrcola/translate.h" #include + +#include +#include diff --git a/lib/libZRColaUI/include/zrcolaui/chargroup.h b/lib/libZRColaUI/include/zrcolaui/chargroup.h index fd89fa3..3713d27 100644 --- a/lib/libZRColaUI/include/zrcolaui/chargroup.h +++ b/lib/libZRColaUI/include/zrcolaui/chargroup.h @@ -24,6 +24,7 @@ #include #include +#include #include #pragma warning(push) @@ -126,34 +127,66 @@ namespace ZRCola { const ZRCola::recordid_t stdex::idrec::record::id = *(ZRCola::recordid_t*)"CGR"; +/// +/// Writes character group database to a stream +/// +/// \param[in] stream Output stream +/// \param[in] db Character group database +/// +/// \returns The stream \p stream +/// +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::chrgrp_db &db) +{ + // Write rank index. + if (stream.fail()) return stream; + stream << db.idxRnk; + + // Write data count. + std::vector::size_type data_count = db.data.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (data_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)data_count; + stream.write((const char*)&count, sizeof(count)); + + // Write data. + if (stream.fail()) return stream; + stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); + + return stream; +} + + /// /// Reads character group database from a stream /// -/// \param[in] stream Input stream +/// \param[in ] stream Input stream /// \param[out] db Character group database /// /// \returns The stream \p stream /// inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::chrgrp_db &db) { - unsigned __int32 count; - - // Read index count. - stream.read((char*)&count, sizeof(count)); - if (!stream.good()) return stream; - // Read rank index. - db.idxRnk.resize(count); - stream.read((char*)db.idxRnk.data(), sizeof(unsigned __int32)*count); + stream >> db.idxRnk; if (!stream.good()) return stream; // Read data count. + unsigned __int32 count; stream.read((char*)&count, sizeof(count)); if (!stream.good()) return stream; - // Read data. - db.data.resize(count); - stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + if (count) { + // Read data. + db.data.resize(count); + stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + } else + db.data.clear(); return stream; } diff --git a/lib/libZRColaUI/include/zrcolaui/keyboard.h b/lib/libZRColaUI/include/zrcolaui/keyboard.h index fe46a94..fee2114 100644 --- a/lib/libZRColaUI/include/zrcolaui/keyboard.h +++ b/lib/libZRColaUI/include/zrcolaui/keyboard.h @@ -27,6 +27,7 @@ #include #include +#include #include #pragma warning(push) @@ -244,39 +245,74 @@ namespace ZRCola { const ZRCola::recordid_t stdex::idrec::record::id = *(ZRCola::recordid_t*)"KEY"; +/// +/// Writes key sequence database to a stream +/// +/// \param[in] stream Output stream +/// \param[in] db Key sequence database +/// +/// \returns The stream \p stream +/// +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const ZRCola::keyseq_db &db) +{ + // Write character index. + if (stream.fail()) return stream; + stream << db.idxChr; + + // Write key index. + if (stream.fail()) return stream; + stream << db.idxKey; + + // Write data count. + std::vector::size_type data_count = db.data.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (data_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)data_count; + stream.write((const char*)&count, sizeof(count)); + + // Write data. + if (stream.fail()) return stream; + stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count); + + return stream; +} + + /// /// Reads key sequence database from a stream /// /// \param[in] stream Input stream -/// \param[out] db Key sequence database +/// \param[out] db Key sequence database /// /// \returns The stream \p stream /// inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::keyseq_db &db) { - unsigned __int32 count; - - // Read index count. - stream.read((char*)&count, sizeof(count)); - if (!stream.good()) return stream; - // Read character index. - db.idxChr.resize(count); - stream.read((char*)db.idxChr.data(), sizeof(unsigned __int32)*count); + stream >> db.idxChr; if (!stream.good()) return stream; // Read key index. - db.idxKey.resize(count); - stream.read((char*)db.idxKey.data(), sizeof(unsigned __int32)*count); + stream >> db.idxKey; if (!stream.good()) return stream; // Read data count. + unsigned __int32 count; stream.read((char*)&count, sizeof(count)); if (!stream.good()) return stream; - // Read data. - db.data.resize(count); - stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + if (count) { + // Read data. + db.data.resize(count); + stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count); + } else + db.data.clear(); return stream; } diff --git a/output/data/ZRCola.zrcdb b/output/data/ZRCola.zrcdb index d087dc8..a025d2e 100644 Binary files a/output/data/ZRCola.zrcdb and b/output/data/ZRCola.zrcdb differ